Initial commit from NXP 2.6.7 sources

NXP is constantly breaking links, but it was found at:
https://www.nxp.com/design/software/development-software/mcuxpresso-software-and-tools-/mcu-bootloader-for-nxp-microcontrollers:MCUBOOT
This commit is contained in:
Keenan Tims 2023-11-05 23:32:03 -08:00
commit 6648373d8e
Signed by: ktims
GPG Key ID: 11230674D69038D4
197 changed files with 48373 additions and 0 deletions

55
SW-Content-Register.txt Normal file
View File

@ -0,0 +1,55 @@
Release Name: blhost
Release Version: 2.6.7
Package License: LA_OPT_NXP_Software_License.htm - Production Use, Section 2.3 applies
Host tools Source Description: Source code for blhost
Author: Freescale
License: Open Source - BSD-3-Clause
Format: source code
Location: src
Host tools - Serial support Description: Windows Serial peripheral support
Author: Bus Pirate Project
License: Open Source - CC0-1.0 (Creative Commons Zero)
URL: http://code.google.com/p/the-bus-pirate/
Format: source code
Location:
src/blfwk/serial.h,
src/blfwk/src/serial.c
Host tools - USB HID Description: Windows USB HID support
support Author: HIDAPI
License: Open Source - BSD-3-Clause
URL: http://github.com/signal11/hidapi
Format: source code
Location:
src/blfwk/hidapi.h,
src/blfwk/src/hid-*.c
Host tools - JSON support Description: Windows JSON support
Author: JSONCPP
License: Open Source - MIT
Format: source code
Location:
src/blfwk/json.h,
src/jsoncpp.cpp
Host tools - options Description: Command line parsing utility
support Author: bradapp@enteract.com
License: Open Source - MIT
URL: http://www.bradapp.com
Format: source code
Location:
src/blfwk/options.h,
src/options.cpp
Host tools - blfwk.lib Description: C++ interface to the Vincent Rijmen's
Rijndael block cipher
Author: Szymon Stefanek (stefanek@tin.it)
License: Public Domain
URL:
http://www.pragmaware.net/software/rijndael/index.php
Format: source code
Location:
src/blfwk/rijndael.h,
src/blfwk/src/rijndael.cpp

BIN
bin/linux/amd64/blhost Executable file

Binary file not shown.

BIN
bin/mac/blhost Normal file

Binary file not shown.

BIN
bin/win/blhost.exe Normal file

Binary file not shown.

BIN
blhost Release Notes.pdf Normal file

Binary file not shown.

Binary file not shown.

126
mk/common.mk Normal file
View File

@ -0,0 +1,126 @@
#-------------------------------------------------------------------------------
# Copyright (c) 2012 Freescale Semiconductor, Inc.
# All rights reserved.
#
# SPDX-License-Identifier: BSD-3-Clause
#-------------------------------------------------------------------------------
#-------------------------------------------------------------------------------
# Utility
#-------------------------------------------------------------------------------
# Kludge to create a variable equal to a single space.
empty :=
space := $(empty) $(empty)
#-------------------------------------------------------------------------------
# OS
#-------------------------------------------------------------------------------
# Get the OS name. Known values are "Linux", "CYGWIN_NT-5.1", and "Darwin".
os_name := $(shell uname -s)
# Set to 1 if running on cygwin.
is_cygwin := $(and $(findstring CYGWIN,$(os_name)),1)
# Set to 1 if running on cygwin.
is_mingw := $(and $(findstring MINGW,$(os_name)),1)
# Set to 1 if running on redhat.
is_redhat := $(shell if [ -f /etc/redhat-release ]; then echo 1 ; fi)
# Disable parallel builds for cygwin since they hang.
ifeq "$(is_cygwin)" "1"
.NOTPARALLEL:
endif
ifeq "$(is_mingw)" "1"
.NOTPARALLEL:
endif
#-------------------------------------------------------------------------------
# Logging options
#-------------------------------------------------------------------------------
# Enable color output by default.
BUILD_SDK_COLOR ?= 1
# MAKE
MAKE := make
ifeq "$(is_cygwin)" "1"
MAKE := mingw32-make
endif
ifeq "$(is_mingw)" "1"
MAKE := mingw32-make
endif
# Normally, commands in recipes are prefixed with '@' so the command itself
# is not echoed by make. But if VERBOSE is defined (set to anything non-empty),
# then the '@' is removed from recipes. The 'at' variable is used to control
# this. Similarly, 'silent_make' is used to pass the -s option to child make
# invocations when not in VERBOSE mode.
ifeq "$(VERBOSE)" "1"
at :=
silent_make :=
else
at := @
silent_make := -s
endif
# These colors must be printed with the printf command. echo won't handle the
# escape sequences.
color_default = \033[00m
color_bold = \033[01m
color_red = \033[31m
color_green = \033[32m
color_yellow = \033[33m
color_blue = \033[34m
color_magenta = \033[35m
color_cyan = \033[36m
color_orange = \033[38;5;172m
color_light_blue = \033[38;5;039m
color_gray = \033[38;5;008m
color_purple = \033[38;5;097m
ifeq "$(BUILD_SDK_COLOR)" "1"
color_build := $(color_light_blue)
color_c := $(color_green)
color_cxx := $(color_green)
color_cpp := $(color_orange)
color_asm := $(color_magenta)
color_ar := $(color_yellow)
color_link := $(color_purple)
endif
# Used in printmessage if the color args are not present.
color_ :=
# Use in recipes to print color messages if printing to a terminal. If
# BUILD_SDK_COLOR is not set to 1, this reverts to a simple uncolorized printf.
# A newline is added to the end of the printed message.
#
# Arguments:
# 1 - name of the color variable (see above), minus the "color_" prefix
# 2 - first colorized part of the message
# 3 - first uncolorized part of the message
# 4 - color name for second colorized message
# 5 - second colorized message
# 6 - second uncolorized part of the message
# 7 - uncolorized prefix on the whole line; this is last because it is expected to be used rarely
#
# All arguments are optional.
#
# Use like:
# $(call printmessage,cyan,Building, remainder of the message...)
ifeq "$(BUILD_SDK_COLOR)" "1"
define printmessage
if [ -t 1 ]; then printf "$(7)$(color_$(1))$(2)$(color_default)$(3)$(color_$(4))$(5)$(color_default)$(6)\n" ; \
else printf "$(7)$(2)$(3)$(5)$(6)\n" ; fi
endef
else
define printmessage
printf "$(7)$(2)$(3)$(5)$(6)\n" ; fi
endef
endif

149
src/blfwk/AESCounter.h Normal file
View File

@ -0,0 +1,149 @@
/*
* File: AESCounter.h
*
* Copyright (c) 2015 Freescale Semiconductor, Inc.
* All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#if !defined(_AESCounter_h_)
#define _AESCounter_h_
#include <string.h>
#include <iostream>
#include "Random.h"
//! An AES-128 counter is 128 bits, or 16 bytes.
typedef uint8_t aes128_counter_t[16];
/*!
* \brief Base class for AESCounter<S>.
*
* This class implements some bigger, non-template methods used in the
* AESCounter<S> templated subclass.
*/
class AESCounterBase
{
public:
//! \brief Reads hex encoded data from \a stream.
void _readFromStream(std::istream &stream, unsigned bytes, uint8_t *buffer);
//! \brief Writes hex encoded data to \a stream.
void _writeToStream(std::ostream &stream, unsigned bytes, const uint8_t *buffer) const;
};
/*!
* \brief Generic AES Counter class.
*
* The template parameter \a S is the number of bits in the counter.
*
* The underlying counter type can be accessed like this: AESCounter<128>::counter_t
*
* When a counter instance is destroyed, it erases the counter data by setting it
* to all zeroes.
*
* \todo Add a way to allow only counter sizes of 128, 192, and 256 bits.
* \todo Find a cross platform way to prevent the counter data from being written
* to the VM swapfile.
*
* AESCounter<128> counter = AESCounter<128>::readFromStream(s);
*/
template <int S>
class AESCounter : public AESCounterBase
{
public:
//! Type for this size of AES counter.
typedef uint8_t counter_t[S / 8];
public:
//! \brief Default constructor.
//!
//! Initializes the counter to 0.
AESCounter() { memset(m_counter, 0, sizeof(m_counter)); }
//! \brief Constructor taking a counter value reference.
AESCounter(const counter_t &counter) { memcpy(m_counter, &counter, sizeof(m_counter)); }
// \brief Constructor taking a counter value pointer.
AESCounter(const counter_t *counter) { memcpy(m_counter, counter, sizeof(m_counter)); }
//! \brief Constructor, reads counter from stream in hex format.
AESCounter(std::istream &stream) { readFromStream(stream); }
//! \brief Copy constructor.
AESCounter(const AESCounter<S> &other) { memcpy(m_counter, other.m_counter, sizeof(m_counter)); }
//! \brief Destructor.
//!
//! Sets the counter value to zero.
~AESCounter() { memset(m_counter, 0, sizeof(m_counter)); }
//! \brief Set to the counter to a randomly generated value.
void randomize()
{
RandomNumberGenerator rng;
rng.generateBlock(m_counter, sizeof(m_counter));
}
//! \brief Reads the counter from a hex encoded data stream.
void readFromStream(std::istream &stream)
{
_readFromStream(stream, S / 8, reinterpret_cast<uint8_t *>(&m_counter));
}
//! \brief Writes the counter to a data stream in hex encoded format.
void writeToStream(std::ostream &stream) const
{
_writeToStream(stream, S / 8, reinterpret_cast<const uint8_t *>(&m_counter));
}
//! \brief Increments the counter by val
void incrementCounter(unsigned val)
{
for (unsigned j = 0; j < val; j++)
{
for (int i = sizeof(AESCounter<S>::counter_t) - 1, carry = 1; (i >= 0) && carry; i--)
{
carry = !++m_counter[i];
}
}
}
//! \name Counter accessors
//@{
inline const counter_t &getCounter() const { return m_counter; }
inline void getCounter(counter_t *counter) const { memcpy(counter, m_counter, sizeof(m_counter)); }
inline void setCounter(const counter_t &counter) { memcpy(m_counter, &counter, sizeof(m_counter)); }
inline void setCounter(const counter_t *counter) { memcpy(m_counter, counter, sizeof(m_counter)); }
inline void setCounter(const AESCounter<S> &counter) { memcpy(m_counter, counter.m_counter, sizeof(m_counter)); }
//@}
//! \name Operators
//@{
const AESCounter<S> &operator=(const AESCounter<S> &counter)
{
setCounter(counter);
return *this;
}
const AESCounter<S> &operator=(const counter_t &counter)
{
setCounter(counter);
return *this;
}
const AESCounter<S> &operator=(const counter_t *counter)
{
setCounter(counter);
return *this;
}
operator const counter_t &() const { return m_counter; }
operator const counter_t *() const { return m_counter; }
friend std::ostream &operator<<(std::ostream &os, const AESCounter<S> &counter)
{
counter.writeToStream(os);
return os;
}
//@}
protected:
counter_t m_counter; //!< The counter value.
};
//! Standard type definition for an AES-128 counter.
typedef AESCounter<128> AES128Counter;
#endif // _AESCounter_h_

134
src/blfwk/AESKey.h Normal file
View File

@ -0,0 +1,134 @@
/*
* File: AESKey.h
*
* Copyright (c) 2015 Freescale Semiconductor, Inc.
* All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#if !defined(_AESKey_h_)
#define _AESKey_h_
#include <string.h>
#include <iostream>
#include "Random.h"
//! An AES-128 key is 128 bits, or 16 bytes.
typedef uint8_t aes128_key_t[16];
/*!
* \brief Base class for AESKey<S>.
*
* This class implements some bigger, non-template methods used in the
* AESKey<S> templated subclass.
*/
class AESKeyBase
{
public:
//! \brief Reads hex encoded data from \a stream.
void _readFromStream(std::istream &stream, unsigned bytes, uint8_t *buffer) const;
//! \brief Writes hex encoded data to \a stream.
void _writeToStream(std::ostream &stream, unsigned bytes, const uint8_t *buffer) const;
};
/*!
* \brief Generic AES key class.
*
* The template parameter \a S is the number of bits in the key.
*
* The underlying key type can be accessed like this: AESKey<128>::key_t
*
* When a key instance is destroyed, it erases the key data by setting it
* to all zeroes.
*
* \todo Add a way to allow only key sizes of 128, 192, and 256 bits.
* \todo Find a cross platform way to prevent the key data from being written
* to the VM swapfile.
*
* AESKey<128> key = AESKey<128>::readFromStream(s);
*/
template <int S>
class AESKey : public AESKeyBase
{
public:
//! Type for this size of AES key.
typedef uint8_t key_t[S / 8];
public:
//! \brief Default constructor.
//!
//! Initializes the key to 0.
AESKey() { memset(m_key, 0, sizeof(m_key)); }
//! \brief Constructor taking a key value reference.
AESKey(const key_t &key) { memcpy(m_key, &key, sizeof(m_key)); }
// \brief Constructor taking a key value pointer.
AESKey(const key_t *key) { memcpy(m_key, key, sizeof(m_key)); }
//! \brief Constructor, reads key from stream in hex format.
AESKey(std::istream &stream) { readFromStream(stream); }
//! \brief Copy constructor.
AESKey(const AESKey<S> &other) { memcpy(m_key, other.m_key, sizeof(m_key)); }
//! \brief Destructor.
//!
//! Sets the key value to zero.
~AESKey() { memset(m_key, 0, sizeof(m_key)); }
//! \brief Set to the key to a randomly generated value.
void randomize()
{
RandomNumberGenerator rng;
rng.generateBlock(m_key, sizeof(m_key));
}
//! \brief Reads the key from a hex encoded data stream.
void readFromStream(std::istream &stream) { _readFromStream(stream, S / 8, reinterpret_cast<uint8_t *>(&m_key)); }
//! \brief Writes the key to a data stream in hex encoded format.
void writeToStream(std::ostream &stream) const
{
_writeToStream(stream, S / 8, reinterpret_cast<const uint8_t *>(&m_key));
}
//! \name Key accessors
//@{
inline const key_t &getKey() const { return m_key; }
inline void getKey(key_t *key) const { memcpy(key, m_key, sizeof(m_key)); }
inline void setKey(const key_t &key) { memcpy(m_key, &key, sizeof(m_key)); }
inline void setKey(const key_t *key) { memcpy(m_key, key, sizeof(m_key)); }
inline void setKey(const AESKey<S> &key) { memcpy(m_key, key.m_key, sizeof(m_key)); }
//@}
//! \name Operators
//@{
const AESKey<S> &operator=(const AESKey<S> &key)
{
setKey(key);
return *this;
}
const AESKey<S> &operator=(const key_t &key)
{
setKey(key);
return *this;
}
const AESKey<S> &operator=(const key_t *key)
{
setKey(key);
return *this;
}
operator const key_t &() const { return m_key; }
operator const key_t *() const { return m_key; }
friend std::ostream &operator<<(std::ostream &os, const AESKey<S> &key)
{
key.writeToStream(os);
return os;
}
//@}
protected:
key_t m_key; //!< The key value.
};
//! Standard type definition for an AES-128 key.
typedef AESKey<128> AES128Key;
#endif // _AESKey_h_

36
src/blfwk/BlfwkErrors.h Normal file
View File

@ -0,0 +1,36 @@
/*
* File: BlfwkErrors.h
*
* Copyright (c) 2015 Freescale Semiconductor, Inc.
* All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#if !defined(_BlfwkErrors_h_)
#define _BlfwkErrors_h_
#include <string>
#include <stdexcept>
//! @addtogroup host_error
//! @{
namespace blfwk
{
/*!
* \brief A semantic error discovered while processing the command file AST.
*/
class semantic_error : public std::runtime_error
{
public:
explicit semantic_error(const std::string &msg)
: std::runtime_error(msg)
{
}
};
}; // namespace blfwk
//! @}
#endif // _BlfwkErrors_h_

70
src/blfwk/Blob.h Normal file
View File

@ -0,0 +1,70 @@
/*
* Copyright (c) 2013-2014 Freescale Semiconductor, Inc.
* All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#if !defined(_Blob_h_)
#define _Blob_h_
#include "stdafx.h"
//! \class Blob
//!
//! \brief Manages a binary object of arbitrary length.
//!
//! The data block is allocated with malloc() instead of the new
//! operator so that we can use realloc() to resize it.
//!
class Blob
{
public:
//! \brief Default constructor.
Blob();
//! \brief Constructor.
Blob(const uint8_t *data, unsigned length);
//! \brief Copy constructor.
Blob(const Blob &other);
//! \brief Destructor.
virtual ~Blob();
//! \name Operations
//@{
//! \brief Replaces the blob's data.
void setData(const uint8_t *data, unsigned length);
//! \brief Change the size of the blob's data.
void setLength(unsigned length);
//! \brief Adds data to the end of the blob.
void append(const uint8_t *newData, unsigned newDataLength);
//! \brief Disposes of the data.
void clear();
//! \brief Tell the blob that it no longer owns its data.
void relinquish();
//@}
//! \name Accessors
//@{
uint8_t *getData() { return m_data; }
const uint8_t *getData() const { return m_data; }
unsigned getLength() const { return m_length; }
//@}
//! \name Operators
//@{
operator uint8_t *() { return m_data; }
operator const uint8_t *() const { return m_data; }
//@}
protected:
uint8_t *m_data; //!< The binary data held by this object.
unsigned m_length; //!< Number of bytes pointed to by #m_data.
};
#endif // _Blob_h_

117
src/blfwk/Bootloader.h Normal file
View File

@ -0,0 +1,117 @@
/*
* Copyright (c) 2013-2014 Freescale Semiconductor, Inc.
* All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef _Bootloader_h_
#define _Bootloader_h_
#include "Command.h"
#include "Packetizer.h"
#include "Peripheral.h"
#include "Logging.h"
#include <string.h>
#include <time.h>
//! @addtogroup blfwk
//! @{
namespace blfwk
{
/*!
* @brief Represents the host bootloader.
*
* This class provides a convenient way to access other bootloader
* framework objects.
*/
class Bootloader
{
public:
//! @brief Default Constructor for Simulator.
Bootloader();
//! @brief Constructor.
Bootloader(const Peripheral::PeripheralConfigData &config);
//! @brief Destructor.
virtual ~Bootloader();
//! @brief Inject a command into the bootloader.
//!
//! @param cmd The command to send
void inject(Command &cmd)
{
clock_t start = clock();
cmd.sendTo(*m_hostPacketizer);
clock_t finish = clock();
Log::debug(" - took %2.3f seconds\n", (double)(finish - start) / CLOCKS_PER_SEC);
}
//! @brief Flush state.
void flush();
//! \brief Execute the execute command.
void execute(uint32_t entry_point, uint32_t param = 0, uint32_t stack_pointer = 0);
//! \brief Execute the reset command.
void reset();
//! \brief get Device's property by using get-property command.
//!
//! \exception std::runtime_error Thrown if an error occurred while sending the
//! GetProperty(property) bootloader command.
//!
//! \param property tag The property tag
//!
//! \param memoryIdorIndex memoryId is required by GetProperty 25(External attribute)
//! Index is required by GetProperty 14/15(RAM start addr/RAM size)
//!
//! \return vector of the response values.
uint32_vector_t getProperty(property_t tag, uint32_t memoryIdorIndex = kMemoryInternal);
//! \brief Checks if Bootloader device supports a given command.
//!
//! \exception std::runtime_error Thrown if an error occurred while sending the
//! GetProperty(kProperty_AvailableCommands) bootloader command.
//!
//! \param command The command to check.
//!
//! \return true if command is supported, false if not.
bool isCommandSupported(const cmd_t &command);
//! \brief Execute the get-property(current-version) command.
standard_version_t getVersion();
//! \brief Execute the get-property(flash-security-state) command.
uint32_t getSecurityState();
//! \brief Execute the get-property(max-supported-packet-size) command.
uint32_t getDataPacketSize();
//! \brief Send a ping if applicable.
void ping(int retries, unsigned int delay, int comSpeed, int* actualComSpeed);
//! @name Accessors.
//@{
//! @brief Get the host packetizer.
Packetizer *getPacketizer() const { return m_hostPacketizer; }
//@}
protected:
Packetizer *m_hostPacketizer; //!< Packet interface to send commands on.
FileLogger *m_logger; //!< Singleton logger instance.
};
} // namespace blfwk
//! @}
#endif // _Bootloader_h_
////////////////////////////////////////////////////////////////////////////////
// EOF
////////////////////////////////////////////////////////////////////////////////

304
src/blfwk/BusPal.h Normal file
View File

@ -0,0 +1,304 @@
/*
* Copyright (c) 2013-2014 Freescale Semiconductor, Inc.
* All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef _BusPal_h_
#define _BusPal_h_
#include "host_types.h"
//! @addtogroup bus_pal
//! @{
namespace blfwk
{
/*!
* @brief Interface with the BusPal.
*
* For hardware documentation, see http://dangerousprototypes.com/docs/Bus_Pirate.
* This class is based on the pyBusPirateLite python package, see
* http://dangerousprototypes.com/docs/Bus_Pirate_Scripting_in_Python.
*/
class BusPal
{
public:
//! @brief Constants.
enum
{
kResetCount = 20, //!< Max number of nulls to send to enter BBIO mode
kResponseOk = 0x01, //!< Successful command response
kBulkTransferMax = 4096, //!< Max number of bytes per bulk transfer
kMaxResponse = kBulkTransferMax //!< Max number of bytes in command response, including bulk transfer response,
//!plus some padding
};
//! @brief BusPal Transports.
enum bus_pal_function_t
{
kBusPalFunction_None,
kBusPalFunction_SPI,
kBusPalFunction_I2C,
kBusPalFunction_CAN,
kBusPalFunction_SAI,
kBusPalFunction_GPIO_CONFIG,
kBusPalFunction_GPIO_SET,
kBusPalFunction_FPGA_CLOCK_SET
};
//! @brief SPI clock polarity configuration.
enum spi_clock_polarity_t
{
kSpiClockPolarity_ActiveHigh = 0, //!< Active-high SPI clock (idles low).
kSpiClockPolarity_ActiveLow = 1 //!< Active-low SPI clock (idles high).
};
//! @brief SPI clock phase configuration.
enum spi_clock_phase_t
{
kSpiClockPhase_FirstEdge =
0, //!< First edge on SPSCK occurs at the middle of the first cycle of a data transfer.
kSpiClockPhase_SecondEdge =
1 //!< First edge on SPSCK occurs at the start of the first cycle of a data transfer.
};
//! @brief SPI data shifter direction options.
enum spi_shift_direction_t
{
kSpiMsbFirst = 0, //!< Data transfers start with most significant bit.
kSpiLsbFirst = 1 //!< Data transfers start with least significant bit.
};
//! @brief Define the SAI bus type
enum sai_protocol_t
{
kSaiProtocol_BusLeftJustified = 0, /*!< Uses left justified format.*/
kSaiProtocol_BusRightJustified = 1, /*!< Uses right justified format. */
kSaiProtocol_BusI2S = 2, /*!< Uses I2S format. */
kSaiProtocol_BusPCMA = 3, /*!< Uses I2S PCM A format.*/
kSaiProtocol_BusPCMB = 4 /*!< Uses I2S PCM B format. */
};
//! @brief Mono or stereo audio format
enum sai_mono_stereo_t
{
kSaiMonoStereo_Stereo = 0, /*!< Stereo sound. */
kSaiMonoStereo_MonoRight = 1, /*!< Only Right channel have sound. */
kSaiMonoStereo_MonoLeft = 2 /*!< Only left channel have sound. */
};
//! @brief I2C default address.
static const uint8_t kBusPalDefaultI2cSlaveAddress = 0x10; // I2C Slave 7-bit address
public:
//! @brief BusPal configuration data.
struct BusPalConfigData
{
bus_pal_function_t function;
uint32_t spiSpeedKHz;
spi_clock_polarity_t spiPolarity;
spi_clock_phase_t spiPhase;
spi_shift_direction_t spiDirection;
uint8_t i2cAddress;
uint32_t i2cSpeedKHz;
uint32_t canSpeed;
uint32_t canTxid;
uint32_t canRxid;
uint32_t saiSpeedHz;
sai_protocol_t saiProtocol;
sai_mono_stereo_t saiStereo;
uint8_t reserved0[2];
uint8_t gpioPort;
uint8_t gpioPinNum;
uint8_t gpioLevel;
uint8_t gpioMux;
uint32_t fpgaClockMhz;
BusPalConfigData(bus_pal_function_t bus = BusPal::kBusPalFunction_None)
: function(bus)
{
spiSpeedKHz = 100;
spiPolarity = BusPal::kSpiClockPolarity_ActiveLow;
spiPhase = BusPal::kSpiClockPhase_SecondEdge;
spiDirection = BusPal::kSpiMsbFirst;
i2cAddress = BusPal::kBusPalDefaultI2cSlaveAddress;
i2cSpeedKHz = 100;
canSpeed = 4; // 4: 1M
canTxid = 0x321;
canRxid = 0x123;
saiSpeedHz = 8000;
saiProtocol = BusPal::kSaiProtocol_BusI2S;
saiStereo = BusPal::kSaiMonoStereo_Stereo;
gpioPort = 0;
gpioPinNum = 0;
gpioLevel = 0;
gpioMux = 0;
fpgaClockMhz = 0;
}
};
//! @brief Constructor.
BusPal(int fileDescriptor);
//! @brief Destructor.
virtual ~BusPal(){};
//! @brief parse the passed in options into the config structure.
static bool parse(const string_vector_t &params, BusPal::BusPalConfigData &config);
//! @brief Reset to bit bang mode from another peripheral mode.
virtual bool reset();
//! @brief Reset the bus pal, comes up in terminal mode.
virtual bool resetHardware();
//! @brief Enter bit bang (binary scripting) mode.
//!
//! Call this first before entering other peripheral modes.
virtual bool enterBitBangMode();
//! @brief Enter Spi mode.
virtual bool enterSpiMode();
//! @brief Enter Can mode.
virtual bool enterCanMode();
//! @brief Enter I2c mode.
virtual bool enterI2cMode();
//! @brief Enter Sai mode.
virtual bool enterSaiMode();
//! @brief Enter Uart mode. Not currently supported for bus pal
virtual bool enterUartMode() { return false; }
//! @brief Enter 1wire mode. Not currently supported for bus pal
virtual bool enter1WireMode() { return false; }
//! @brief Enter raw wire mode. Not currently supported for bus pal
virtual bool enterRawWireMode() { return false; }
//! @brief Raw configure pins.
virtual bool rawConfigurePins(uint8_t port, uint8_t pin, uint8_t muxVal);
//! @brief Set GPIO pin
virtual bool rawSetPins(uint8_t port, uint8_t pin, uint8_t level);
//! @brief Configure pins.
virtual bool configurePins(uint8_t config = 0) { return true; }
//! @brief Read pins.
virtual uint8_t readPins() { return 0; }
//! @brief Sets the FPGA clock, clock is in hertz
virtual bool setFPGAClock(uint32_t clock);
//! @brief Set SPI speed.
virtual bool setSpiSpeed(unsigned int speed);
//! @brief Sets the SPI configuration
virtual bool setSpiConfig(spi_clock_polarity_t polarity, spi_clock_phase_t phase, spi_shift_direction_t direction);
//! @brief Set I2c address
virtual bool setI2cAddress(uint8_t address);
//! @brief Set I2c speed
virtual bool setI2cSpeed(uint32_t speed);
//! @brief Set CAN speed.
virtual bool setCanSpeed(unsigned int speed);
//! @brief Set CAN txid.
virtual bool setCanTxid(unsigned int txid);
//! @brief Set CAN rxid.
virtual bool setCanRxid(unsigned int rxid);
//! @brief Set SAI speed.
virtual bool setSaiSpeed(unsigned int speed);
//! @brief Sets the SAI configuration
virtual bool setSaiConfig(sai_protocol_t protocol, sai_mono_stereo_t stereo);
//! @brief Read response.
//!
//! @retval NULL No response from device
//! @retval Non-NULL Pointer to internal array of bytes at least size byteCount
virtual uint8_t *response(size_t byteCount = 1);
//! @brief writes the data over the previously selected interface
virtual bool write(const uint8_t *data, size_t byteCount = 1);
//! @brief Read data.
virtual int read(uint8_t *data, size_t byteCount);
protected:
//! @brief Write command, check string response.
virtual bool writeCommand(uint8_t commandByte, const char *expectedResponse);
//! @brief Write command, return 1 byte response.
virtual uint8_t writeCommand(uint8_t commandByte);
//! @brief write multi-byte command, return 1 byte response.
virtual uint8_t writeCommand(uint8_t *command, unsigned int length);
//! @brief write via Spi
virtual bool writeSpi(const uint8_t *data, size_t byteCount = 1);
//! @brief write via I2c
virtual bool writeI2c(const uint8_t *data, size_t byteCount = 1);
//! @brief write via Can
virtual bool writeCan(const uint8_t *data, size_t byteCount = 1);
//! @brief write via Sai
virtual bool writeSai(const uint8_t *data, size_t byteCount = 1);
//! @brief read via Spi
virtual int readSpi(uint8_t *data, size_t byteCount);
//! @brief read via Can
virtual int readCan(uint8_t *data, size_t byteCount);
//! @brief worker function to actually read SPI data
int readSpiActual(uint8_t *data, size_t byteCount);
//! @brief read via I2c
virtual int readI2c(uint8_t *data, size_t byteCount);
//! @brief read via Sai
virtual int readSai(uint8_t *data, size_t byteCount);
//! @brief Overriden serial_read for logging
int buspal_serial_read(uint8_t *buf, int size, bool isCommandData = false);
//! @brief Overriden serial_write for logging
int buspal_serial_write(uint8_t *buf, int size, bool isCommandData = false);
//! @brief Flushes the serial port of any RX data
void flushRX();
protected:
enum bus_pal_mode_t
{
kBusPalModeBitBang,
kBusPalModeSpi,
kBusPalModeI2c,
kBusPalModeCan,
kBusPalModeSai
};
int m_fileDescriptor; //!< PC COM port file descriptor.
uint8_t m_responseBuffer[kMaxResponse]; //!< Command response buffer.
bus_pal_mode_t m_mode;
unsigned int m_spiWriteByteCount;
unsigned int m_canWriteByteCount;
unsigned int m_canFirstReadDelay;
unsigned int m_saiWriteByteCount;
};
} // namespace blfwk
//! @}
#endif // _BusPal_h_
////////////////////////////////////////////////////////////////////////////////
// EOF
////////////////////////////////////////////////////////////////////////////////

View File

@ -0,0 +1,67 @@
/*
* Copyright (c) 2013-2014 Freescale Semiconductor, Inc.
* All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef _BusPalPeripheral_h_
#define _BusPalPeripheral_h_
#include "UartPeripheral.h"
#include "BusPal.h"
//! @addtogroup bus_pal_peripheral
//! @{
namespace blfwk
{
/*!
* @brief Peripheral that talks to the target device over BusPal UART hardware.
*/
class BusPalUartPeripheral : public UartPeripheral
{
public:
//! @brief Parameterized constructor that opens the serial port.
//!
//! Opens and configures the port. Throws exception if port configuration fails.
//!
//! Note: following COM port configuration is assumed: 8 bits, 1 stop bit, no parity.
//!
//! @param port OS file path for COM port. For example "COM1" on Windows.
//! @param speed Port speed, e.g. 9600.
BusPalUartPeripheral(const char *port, long speed, const BusPal::BusPalConfigData &config);
//! @brief Destructor.
virtual ~BusPalUartPeripheral();
//! @brief configure the bus pal with the passed in options
void configure(const BusPal::BusPalConfigData &config);
//! @brief Read bytes.
//!
//! @param buffer Pointer to buffer
//! @param requestedBytes Number of bytes to read
virtual status_t read(uint8_t *buffer, uint32_t requestedBytes, uint32_t *actualBytes, uint32_t timeoutMs);
//! @brief Write bytes.
//!
//! @param buffer Pointer to buffer to write
//! @param byteCount Number of bytes to write
virtual status_t write(const uint8_t *buffer, uint32_t byteCount);
virtual _host_peripheral_types get_type(void) { return kHostPeripheralType_BUSPAL_UART; }
protected:
BusPal *m_busPal; //!< Represents Bus Pal hardware.
};
} // namespace blfwk
//! @}
#endif // _BusPalPeripheral_h_
////////////////////////////////////////////////////////////////////////////////
// EOF
////////////////////////////////////////////////////////////////////////////////

2135
src/blfwk/Command.h Normal file

File diff suppressed because it is too large Load Diff

40
src/blfwk/Crc.h Normal file
View File

@ -0,0 +1,40 @@
/*
* Copyright (c) 2013-2015 Freescale Semiconductor, Inc.
* All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#if !defined(_Crc_h_)
#define _Crc_h_
#include <stdint.h>
namespace blfwk
{
/*!
* \brief Crc class contains the functionality about crc ccalculation.
*/
class Crc
{
public:
//! \brief Default constructor.
Crc(){};
//! \brief Destructor.
virtual ~Crc(){};
//! \brief calculate crc32 for a given memory region
//!
//! \param start The start address of a memory region that contains the data
//! \
//! \param length Length in bytes to calculate
//! \
//! \return calculated result
static uint32_t calculate_application_crc32(const uint8_t *start, uint32_t length);
//@}
//
};
} // namespace blfwk
#endif // _Crc_h_

303
src/blfwk/DataSource.h Normal file
View File

@ -0,0 +1,303 @@
/*
* Copyright (c) 2013-2014 Freescale Semiconductor, Inc.
* All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#if !defined(_DataSource_h_)
#define _DataSource_h_
#include <vector>
#include "Value.h"
#include "smart_ptr.h"
#include "StExecutableImage.h"
namespace blfwk
{
// Forward declaration
class DataTarget;
/*!
* \brief Abstract base class for data sources.
*
* Data sources represent any sort of data that can be placed or loaded
* into a target region. Sources may be a single blob of data read from
* a file or may consist of many segments.
*
* The three most important features of data sources are:
* - Sources may be multi-segmented.
* - Sources and/or segments can have a "natural" or default target location.
* - The target for a source may be taken into consideration when the source
* describes itself.
*/
class DataSource
{
public:
/*!
* \brief Discrete, contiguous part of the source's data.
*
* This class is purely abstract and subclasses of DataSource are expected
* to subclass it to implement a segment particular to their needs.
*/
class Segment
{
public:
//! \brief Default constructor.
Segment(DataSource &source)
: m_source(source)
{
}
//! \brief Destructor.
virtual ~Segment() {}
//! \brief Gets all or a portion of the segment's data.
//!
//! The data is copied into \a buffer. Up to \a maxBytes bytes may be
//! copied, so \a buffer must be at least that large.
//!
//! \param offset Index of the first byte to start copying from.
//! \param maxBytes The maximum number of bytes that can be returned. \a buffer
//! must be at least this large.
//! \param buffer Pointer to buffer where the data is copied.
//! \return The number of bytes copied into \a buffer.
virtual unsigned getData(unsigned offset, unsigned maxBytes, uint8_t *buffer) = 0;
//! \brief Gets the length of the segment's data.
virtual unsigned getLength() = 0;
//! \brief Returns whether the segment has an associated address.
virtual bool hasNaturalLocation() = 0;
//! \brief Returns the address associated with the segment.
virtual uint32_t getBaseAddress() { return 0; }
protected:
DataSource &m_source; //!< The data source to which this segment belongs.
};
/*!
* \brief This is a special type of segment containing a repeating pattern.
*
* By default the segment doesn't have a specific length or data. The length depends
* on the target's address range. And the data is just the pattern, repeated
* many times. In addition, pattern segments do not have a natural location.
*
* Calling code should look for instances of PatternSegment and handle them
* as special cases that can be optimized.
*/
class PatternSegment : public Segment
{
public:
//! \brief Default constructor.
PatternSegment(DataSource &source);
//! \brief Constructor taking a fill pattern.
PatternSegment(DataSource &source, const SizedIntegerValue &pattern);
//! \brief Constructor taking a byte fill pattern.
PatternSegment(DataSource &source, uint8_t pattern);
//! \brief Constructor taking a half-word fill pattern.
PatternSegment(DataSource &source, uint16_t pattern);
//! \brief Constructor taking a word fill pattern.
PatternSegment(DataSource &source, uint32_t pattern);
//! \name Segment methods
//@{
//! \brief Pattern segments have no natural address.
virtual bool hasNaturalLocation() { return false; }
//! \brief Performs a pattern fill into the \a buffer.
virtual unsigned getData(unsigned offset, unsigned maxBytes, uint8_t *buffer);
//! \brief Returns a length based on the data target's address range.
virtual unsigned getLength();
//@}
//! \name Pattern accessors
//@{
//! \brief Assigns a new fill pattern.
inline void setPattern(const SizedIntegerValue &newPattern) { m_pattern = newPattern; }
//! \brief Return the fill pattern for the segment.
inline SizedIntegerValue &getPattern() { return m_pattern; }
//! \brief Assignment operator, sets the pattern value and length.
PatternSegment &operator=(const SizedIntegerValue &value)
{
m_pattern = value;
return *this;
}
//@}
protected:
SizedIntegerValue m_pattern; //!< The fill pattern.
};
public:
//! \brief Default constructor.
DataSource()
: m_target(0)
{
}
//! \brief Destructor.
virtual ~DataSource() {}
//! \name Data target
//@{
//! \brief Sets the associated data target.
inline void setTarget(DataTarget *target) { m_target = target; }
//! \brief Gets the associated data target.
inline DataTarget *getTarget() const { return m_target; }
//@}
//! \name Segments
//@{
//! \brief Returns the number of segments in this data source.
virtual unsigned getSegmentCount() = 0;
//! \brief Returns segment number \a index of the data source.
virtual Segment *getSegmentAt(unsigned index) = 0;
//@}
protected:
DataTarget *m_target; //!< Corresponding target for this source.
};
/*!
* \brief Data source for a repeating pattern.
*
* The pattern is represented by a SizedIntegerValue object. Thus the pattern
* can be either byte, half-word, or word sized.
*
* This data source has only one segment, and the PatternSource instance acts
* as its own single segment.
*/
class PatternSource : public DataSource, public DataSource::PatternSegment
{
public:
//! \brief Default constructor.
PatternSource();
//! \brief Constructor taking the pattern value.
PatternSource(const SizedIntegerValue &value);
//! \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; }
//! \brief Assignment operator, sets the pattern value and length.
PatternSource &operator=(const SizedIntegerValue &value)
{
setPattern(value);
return *this;
}
};
/*!
* \brief Data source for data that is not memory mapped (has no natural address).
*
* This data source can only manage a single block of data, which has no
* associated address. It acts as its own Segment.
*/
class UnmappedDataSource : public DataSource, public DataSource::Segment
{
public:
//! \brief Default constructor.
UnmappedDataSource();
//! \brief Constructor taking the data, which is copied.
UnmappedDataSource(const uint8_t *data, unsigned length);
//! \brief Sets the source's data.
void setData(const uint8_t *data, unsigned length);
//! \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 Unmapped data sources have no natural address.
virtual bool hasNaturalLocation() { return false; }
//! \brief Copies a portion of the data into \a buffer.
virtual unsigned getData(unsigned offset, unsigned maxBytes, uint8_t *buffer);
//! \brief Returns the number of bytes of data managed by the source.
virtual unsigned getLength() { return m_length; }
//! \brief Returns the address associated with the segment.
virtual uint32_t getBaseAddress();
//@}
protected:
smart_array_ptr<uint8_t> m_data; //!< The data.
unsigned m_length; //!< Byte count of the data.
};
/*!
* \brief Data source that takes its data from an executable image.
*
* \see StExecutableImage
*/
class MemoryImageDataSource : public DataSource
{
public:
//! \brief Default constructor.
MemoryImageDataSource(StExecutableImage *image);
//! \brief Destructor.
virtual ~MemoryImageDataSource();
//! \brief Returns the number of memory regions in the image.
virtual unsigned getSegmentCount();
//! \brief Returns the data source segment at position \a index.
virtual DataSource::Segment *getSegmentAt(unsigned index);
protected:
/*!
* \brief Segment corresponding to a text region of the executable image.
*/
class TextSegment : public DataSource::Segment
{
public:
//! \brief Default constructor
TextSegment(MemoryImageDataSource &source, StExecutableImage *image, unsigned index);
virtual unsigned getData(unsigned offset, unsigned maxBytes, uint8_t *buffer);
virtual unsigned getLength();
virtual bool hasNaturalLocation() { return true; }
virtual uint32_t getBaseAddress();
protected:
StExecutableImage *m_image; //!< Coalesced image of the file.
unsigned m_index; //!< Record index.
};
/*!
* \brief Segment corresponding to a fill region of the executable image.
*/
class FillSegment : public DataSource::PatternSegment
{
public:
FillSegment(MemoryImageDataSource &source, StExecutableImage *image, unsigned index);
virtual unsigned getLength();
virtual bool hasNaturalLocation() { return true; }
virtual uint32_t getBaseAddress();
protected:
StExecutableImage *m_image; //!< Coalesced image of the file.
unsigned m_index; //!< Record index.
};
protected:
StExecutableImage *m_image; //!< The memory image that is the data source.
typedef std::vector<DataSource::Segment *> segment_array_t; //!< An array of segments.
segment_array_t m_segments; //!< The array of Segment instances.
};
}; // namespace blfwk
#endif // _DataSource_h_

View File

@ -0,0 +1,55 @@
/*
* File: DataSourceImager.h
*
* Copyright (c) 2015 Freescale Semiconductor, Inc.
* All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#if !defined(_DataSourceImager_h_)
#define _DataSourceImager_h_
#include "Blob.h"
#include "DataSource.h"
namespace blfwk
{
/*!
* \brief Converts a DataSource into a single binary buffer.
*/
class DataSourceImager : public Blob
{
public:
//! \brief Constructor.
DataSourceImager();
//! \name Setup
//@{
void setBaseAddress(uint32_t address);
void setFillPattern(uint8_t pattern);
//@}
void reset();
//! \name Accessors
//@{
uint32_t getBaseAddress() { return m_baseAddress; }
//@}
//! \name Operations
//@{
//! \brief Adds all of the segments of which \a dataSource is composed.
void addDataSource(DataSource *source);
//! \brief Adds the data from one data segment.
void addDataSegment(DataSource::Segment *segment);
//@}
protected:
uint8_t m_fill;
uint32_t m_baseAddress;
bool m_isBaseAddressSet;
};
};
#endif // _DataSourceImager_h_

132
src/blfwk/DataTarget.h Normal file
View File

@ -0,0 +1,132 @@
/*
* Copyright (c) 2013-2014 Freescale Semiconductor, Inc.
* All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#if !defined(_DataTarget_h_)
#define _DataTarget_h_
#include "stdafx.h"
#include "DataSource.h"
namespace blfwk
{
// Forward declaration
class DataSource;
/*!
* \brief Abstract base class for the target address or range of data.
*
* Targets at the most basic level have a single address, and potentially
* an address range. Unbounded targets have a beginning address but no
* specific end address, while bounded targets do have an end address.
*
* Users of a data target can access the begin and end addresses directly.
* However, the most powerful way to use a target is with the
* getRangeForSegment() method. This method returns the target address range
* for a segment of a data source. The value of the resulting range can be
* completely dependent upon the segment's properties, those of its data
* source, and the type of data target.
*
* \see blfwk::DataSource
*/
class DataTarget
{
public:
//! \brief Simple structure that describes an addressed region of memory.
//! \todo Decide if the end address is inclusive or not.
struct AddressRange
{
uint32_t m_begin;
uint32_t m_end;
};
public:
//! \brief Default constructor.
DataTarget()
: m_source(0)
{
}
//! \brief Destructor.
virtual ~DataTarget() {}
//! \brief Whether the target is just a single address or has an end to it.
virtual bool isBounded() { return false; }
virtual uint32_t getBeginAddress() { return 0; }
virtual uint32_t getEndAddress() { return 0; }
//! \brief Return the address range for a segment of a data source.
virtual DataTarget::AddressRange getRangeForSegment(DataSource &source, DataSource::Segment &segment) = 0;
inline void setSource(DataSource *source) { m_source = source; }
inline DataSource *getSource() const { return m_source; }
protected:
DataSource *m_source; //!< Corresponding data source for this target.
};
/*!
* \brief Target with a constant values for the addresses.
*
* This target type supports can be both bounded and unbounded. It always has
* at least one address, the beginning address. The end address is optional,
* and if not provided makes the target unbounded.
*/
class ConstantDataTarget : public DataTarget
{
public:
//! \brief Constructor taking only a begin address.
ConstantDataTarget(uint32_t start)
: DataTarget()
, m_begin(start)
, m_end(0)
, m_hasEnd(false)
{
}
//! \brief Constructor taking both begin and end addresses.
ConstantDataTarget(uint32_t start, uint32_t end)
: DataTarget()
, m_begin(start)
, m_end(end)
, m_hasEnd(true)
{
}
//! \brief The target is bounded if an end address was specified.
virtual bool isBounded() { return m_hasEnd; }
virtual uint32_t getBeginAddress() { return m_begin; }
virtual uint32_t getEndAddress() { return m_end; }
//! \brief Return the address range for a segment of a data source.
virtual DataTarget::AddressRange getRangeForSegment(DataSource &source, DataSource::Segment &segment);
protected:
uint32_t m_begin; //!< Start address.
uint32_t m_end; //!< End address.
bool m_hasEnd; //!< Was an end address specified?
};
/*!
* \brief Target address that is the "natural" location of whatever the source data is.
*
* The data source used with the target must have a natural location. If
* getRangeForSegment() is called with a segment that does not have a natural
* location, a semantic_error will be thrown.
*/
class NaturalDataTarget : public DataTarget
{
public:
//! \brief Default constructor.
NaturalDataTarget()
: DataTarget()
{
}
//! \brief Natural data targets are bounded by their source's segment lengths.
virtual bool isBounded() { return true; }
//! \brief Return the address range for a segment of a data source.
virtual DataTarget::AddressRange getRangeForSegment(DataSource &source, DataSource::Segment &segment);
};
}; // namespace blfwk
#endif // _DataTarget_h_

349
src/blfwk/ELF.h Normal file
View File

@ -0,0 +1,349 @@
/*
* Copyright (c) 2013-2014 Freescale Semiconductor, Inc.
* All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#if !defined(_ELF_h_)
#define _ELF_h_
//! \name ELF types
//! Types used in ELF file structures.
//@{
typedef uint32_t Elf32_Addr;
typedef uint16_t Elf32_Half;
typedef /*off_t*/ uint32_t Elf32_Off;
typedef int32_t Elf32_Sword;
typedef uint32_t Elf32_Word;
//@}
// All ELF structures are byte aligned. Any alignment padding is explicit.
#pragma pack(1)
//! \name File header
//@{
/*!
* Constants for the various fields of Elf32_Ehdr.e_ident.
*/
enum
{
EI_MAG0 = 0,
EI_MAG1,
EI_MAG2,
EI_MAG3,
EI_CLASS,
EI_DATA,
EI_VERSION,
EI_PAD,
EI_NIDENT = 16,
// Magic number.
ELFMAG0 = 0x7f,
ELFMAG1 = 'E',
ELFMAG2 = 'L',
ELFMAG3 = 'F',
// EI_CLASS
ELFCLASSNONE = 0,
ELFCLASS32 = 1,
ELFCLASS64 = 2,
// EI_DATA
ELFDATANONE = 0,
ELFDATA2LSB = 1,
ELFDATA2MSB = 2
};
/*!
* \brief ELF file header.
*/
struct Elf32_Ehdr
{
unsigned char e_ident[EI_NIDENT]; //!< Magic number identifying the file format.
Elf32_Half e_type; //!< Identifies the object file format.
Elf32_Half e_machine; //!< Specified the architecture for the object file.
Elf32_Word e_version; //!< Object file version.
Elf32_Addr e_entry; //!< Virtual address of the entry point, or 0.
Elf32_Off e_phoff; //!< Program header table offset in bytes, or 0 if no program header table.
Elf32_Off e_shoff; //!< Section header table offset in bytes, or 0 if no section header table.
Elf32_Word e_flags; //!< Processor-specific flags associated with the file.
Elf32_Half e_ehsize; //!< The ELF header's size in bytes.
Elf32_Half e_phentsize; //!< Size in bytes of one entry in the program header table.
Elf32_Half e_phnum; //!< Number of entries in the program header table.
Elf32_Half e_shentsize; //!< Size in bytes of an entry in the section header table.
Elf32_Half e_shnum; //!< Number of entries in the section header table.
Elf32_Half e_shstrndx; //!< Section header table index of the section name string table.
};
/*!
* Constants for #Elf32_Ehdr.e_type.
*/
enum
{
ET_NONE, //!< No file type.
ET_REL, //!< Relocatable file.
ET_EXEC, //!< Executable file.
ET_DYN, //!< Shared object file.
ET_CORE, //!< Core file.
ET_LOPROC, //!< Low bound of processor-specific file types.
ET_HIPROC //!< High bound of processor-specific file types.
};
/*!
* ARM-specific #Elf32_Ehdr.e_flags
*/
enum
{
EF_ARM_HASENTRY = 0x02, //!< #Elf32_Ehdr.e_entry contains a program-loader entry point.
EF_ARM_SYMSARESORTED = 0x04, //!< Each subsection of the symbol table is sorted by symbol value.
EF_ARM_DYNSYMSUSESEGIDX = 0x08, //!< Symbols in dynamic symbol tables that are defined in sections included in
//!program segment n have #Elf32_Sym.st_shndx = n + 1.
EF_ARM_MAPSYMSFIRST = 0x10, //!< Mapping symbols precede other local symbols in the symbol table.
EF_ARM_EABIMASK = 0xff000000, //!< This masks an 8-bit version number, the version of the ARM EABI to which this ELF
//!file conforms. The current EABI version is #ARM_EABI_VERSION.
ARM_EABI_VERSION = 0x02000000 //!< Current ARM EABI version.
};
//@}
//! \name Sections
//@{
/*!
* \brief ELF section header.
*
* An object file's section header table lets one locate all the file's
* sections. The section header table is an array of #Elf32_Shdr structures.
* A section header table index is a subscript into this array. The ELF
* header's #Elf32_Ehdr::e_shoff member gives the byte offset from the beginning of
* the file to the section header table; #Elf32_Ehdr::e_shnum tells how many entries
* the section header table contains; #Elf32_Ehdr::e_shentsize gives the size in bytes
* of each entry.
*
* Some section header table indexes are reserved. An object file will not
* have sections for these special indexes:
* - #SHN_UNDEF
* - #SHN_LORESERVE
* - #SHN_LOPROC
* - #SHN_HIPROC
* - #SHN_ABS
* - #SHN_COMMON
* - #SHN_HIRESERVE
*/
struct Elf32_Shdr
{
Elf32_Word sh_name; //!< The section's name. Index into the section header string table section.
Elf32_Word sh_type; //!< Section type, describing the contents and semantics.
Elf32_Word sh_flags; //!< Section flags describing various attributes.
Elf32_Addr sh_addr; //!< The address at which the section will appear in the memory image, or 0.
Elf32_Off sh_offset; //!< Offset from beginning of the file to the first byte in the section.
Elf32_Word sh_size; //!< The section's size in bytes.
Elf32_Word sh_link; //!< Section header table link index. Interpretation depends on section type.
Elf32_Word sh_info; //!< Extra information about the section. Depends on section type.
Elf32_Word sh_addralign; //!< Address alignment constraint. Values are 0 and positive powers of 2.
Elf32_Word sh_entsize; //!< Size in bytes of section entries, or 0 if the section does not have fixed-size entries.
};
/*!
* Special section indexes.
*/
enum
{
SHN_UNDEF = 0,
SHN_LORESERVE = 0xff00,
SHN_LOPROC = 0xff00,
SHN_HIPROC = 0xff1f,
SHN_ABS = 0xfff1, //!< The symbol has an absolute value that will not change because of relocation.
SHN_COMMON = 0xfff2, //!< The symbol labels a common block that has not yet been allocated.
SHN_HIRESERVE = 0xffff
};
/*!
* Section type constants.
*/
enum
{
SHT_NULL = 0,
SHT_PROGBITS = 1,
SHT_SYMTAB = 2,
SHT_STRTAB = 3,
SHT_RELA = 4,
SHT_HASH = 5,
SHT_DYNAMIC = 6,
SHT_NOTE = 7,
SHT_NOBITS = 8,
SHT_REL = 9,
SHT_SHLIB = 10,
SHT_DYNSYM = 11
};
/*!
* Section flag constants.
*/
enum
{
SHF_WRITE = 0x1, //!< Section is writable.
SHF_ALLOC = 0x2, //!< Allocate section.
SHF_EXECINSTR = 0x4 //!< Section contains executable instructions.
};
/*!
* ARM-specific section flag constants
*/
enum
{
SHF_ENTRYSECT = 0x10000000, //!< The section contains an entry point.
SHF_COMDEF = 0x80000000 //!< The section may be multiply defined in the input to a link step.
};
#define BSS_SECTION_NAME ".bss"
#define DATA_SECTION_NAME ".data"
#define TEXT_SECTION_NAME ".text"
#define SHSTRTAB_SECTION_NAME ".shstrtab"
#define STRTAB_SECTION_NAME ".strtab"
#define SYMTAB_SECTION_NAME ".symtab"
//@}
//! \name Segments
//@{
/*!
* \brief ELF program header.
*
* An executable or shared object file's program header table is an array of
* structures, each describing a segment or other information the system needs
* to prepare the program for execution. An object file segment contains one
* or more sections. Program headers are meaningful only for executable and
* shared object files. A file specifies its own program header size with the
* ELF header's #Elf32_Ehdr::e_phentsize and #Elf32_Ehdr::e_phnum members.
*/
struct Elf32_Phdr
{
Elf32_Word p_type; //!< What type of segment this header describes.
Elf32_Off p_offset; //!< Offset in bytes from start of file to the first byte of the segment.
Elf32_Addr p_vaddr; //!< Virtual address at which the segment will reside in memory.
Elf32_Addr p_paddr; //!< Physical address, for systems where this is relevant.
Elf32_Word p_filesz; //!< Number of bytes of file data the segment consumes. May be zero.
Elf32_Word p_memsz; //!< Size in bytes of the segment in memory. May be zero.
Elf32_Word p_flags; //!< Flags relevant to the segment.
Elf32_Word p_align; //!< Alignment constraint for segment addresses. Possible values are 0 and positive powers of 2.
};
/*!
* Segment type constants.
*/
enum
{
PT_NULL = 0,
PT_LOAD = 1,
PT_DYNAMIC = 2,
PT_INTERP = 3,
PT_NOTE = 4,
PT_SHLIB = 5,
PT_PHDR = 6
};
/*!
* Program header flag constants.
*/
enum
{
PF_X = 0x1, //!< Segment is executable.
PF_W = 0x2, //!< Segment is writable.
PF_R = 0x4 //!< Segment is readable.
};
//@}
//! \name Symbol table
//@{
enum
{
STN_UNDEF = 0 //!< Undefined symbol index.
};
/*!
* \brief ELF symbol table entry.
*
* An object file's symbol table holds information needed to locate and
* relocate a program's symbolic definitions and references. A symbol
* table index is a subscript into this array. Index 0 both designates
* the first entry in the table and serves as the undefined symbol index.
*/
struct Elf32_Sym
{
Elf32_Word st_name; //!< Index into file's string table.
Elf32_Addr st_value; //!< Value associated with the symbol. Depends on context.
Elf32_Word st_size; //!< Size associated with symbol. 0 if the symbol has no size or an unknown size.
unsigned char st_info; //!< Specified the symbol's type and binding attributes.
unsigned char st_other; //!< Currently 0 (reserved).
Elf32_Half st_shndx; //!< Section header table index for this symbol.
};
//! \name st_info macros
//! Macros for manipulating the st_info field of Elf32_Sym struct.
//@{
#define ELF32_ST_BIND(i) ((i) >> 4) //!< Get binding attributes.
#define ELF32_ST_TYPE(i) ((i)&0x0f) //!< Get symbol type.
#define ELF32_ST_INFO(b, t) \
(((b) << 4) + ((t)&0x0f)) //!< Construct st_info value from binding attributes and symbol type.
//@}
/*!
* \brief Symbol binding attributes.
*
* These constants are mask values.
*/
enum
{
STB_LOCAL = 0, //!< Local symbol not visible outside the object file.
STB_GLOBAL = 1, //!< Symbol is visible to all object files being linked together.
STB_WEAK = 2, //!< Like global symbols, but with lower precedence.
// Processor-specific semantics.
STB_LOPROC = 13,
STB_HIPROC = 15
};
/*!
* \brief Symbol types.
*/
enum
{
STT_NOTYPE = 0, //!< The symbol's type is not specified.
STT_OBJECT = 1, //!< The symbol is associated with a data object, such as a variable or array.
STT_FUNC = 2, //!< The symbol is associated with a function or other executable code.
STT_SECTION = 3, //!< The synmbol is associated with a section. Primarily used for relocation.
STT_FILE = 4, //!< A file symbol has STB_LOCAL binding, its section index is SHN_ABS, and it precedes the other
//!STB_LOCAL symbols for the file, if it is present.
STT_LOPROC = 13, //!< Low bound of processor-specific symbol types.
STT_HIPROC = 15 //!< High bound of processor-specific symbol types.
};
/*!
* GHS-specific constants
*/
enum
{
STO_THUMB = 1 //!< This flag is set on #Elf32_Sym.st_other if the symbol is Thumb mode code.
};
#define ARM_SEQUENCE_MAPSYM "$a"
#define DATA_SEQUENCE_MAPSYM "$d"
#define THUMB_SEQUENCE_MAPSYM "$t"
#define THUMB_BL_TAGSYM "$b"
#define FN_PTR_CONST_TAGSYM "$f"
#define INDIRECT_FN_CALL_TAGSYM "$p"
#define MAPPING_SYMBOL_COUNT_TAGSYM "$m"
//@}
#pragma pack()
#endif // _ELF_h_

228
src/blfwk/ELFSourceFile.h Normal file
View File

@ -0,0 +1,228 @@
/*
* Copyright (c) 2013-2014 Freescale Semiconductor, Inc.
* All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#if !defined(_ELFSourceFile_h_)
#define _ELFSourceFile_h_
#include "SourceFile.h"
#include "StELFFile.h"
#include "smart_ptr.h"
#include "DataSource.h"
#include "DataTarget.h"
#include "ELF.h"
namespace blfwk
{
//! Set of supported compiler toolsets.
enum elf_toolset_t
{
kUnknownToolset, //!< Unknown.
kGHSToolset, //!< Green Hills Software MULTI
kGCCToolset, //!< GNU GCC
kADSToolset //!< ARM UK RealView
};
//! Options for handling the .secinfo section in GHS-produced ELF files.
enum secinfo_clear_t
{
// Default value for the .secinfo action.
kSecinfoDefault,
//! Ignore the .secinfo section if present. The standard ELF loading
//! rules are followed.
kSecinfoIgnore,
//! The boot ROM clears only those SHT_NOBITS sections present in .secinfo.
kSecinfoROMClear,
//! The C startup is responsible for clearing sections. No fill commands
//! are generated for any SHT_NOBITS sections.
kSecinfoCStartupClear
};
/*!
* \brief Executable and Loading Format (ELF) source file.
*/
class ELFSourceFile : public SourceFile
{
public:
//! \brief Default constructor.
ELFSourceFile(const std::string &path);
//! \brief Destructor.
virtual ~ELFSourceFile();
//! \brief Identifies whether the stream contains an ELF file.
static bool isELFFile(std::istream &stream);
//! \name Opening and closing
//@{
//! \brief Opens the file.
virtual void open();
//! \brief Closes the file.
virtual void close();
//@}
//! \name Format capabilities
//@{
virtual bool supportsNamedSections() const { return true; }
virtual bool supportsNamedSymbols() const { return true; }
//@}
//! \name Data source
//@{
//! \brief Creates a data source from the entire file.
virtual DataSource *createDataSource();
//! \brief Creates a data source from one or more sections of the file.
virtual DataSource *createDataSource(StringMatcher &matcher);
//@}
//! \brief Creates a data source from sections of the file that either match or do not match the
// baseAddress
virtual DataSource *createDataSource(const std::vector<uint32_t> &baseAddress, bool match);
//@}
//! \name Entry point
//@{
//! \brief Returns true if an entry point was set in the file.
virtual bool hasEntryPoint();
//! \brief Returns the entry point address.
virtual uint32_t getEntryPointAddress();
//@}
//! \name Data target
//@{
virtual DataTarget *createDataTargetForSection(const std::string &section);
virtual DataTarget *createDataTargetForSymbol(const std::string &symbol);
//@}
//! \name Symbols
//@{
//! \brief Returns whether a symbol exists in the source file.
virtual bool hasSymbol(const std::string &name);
//! \brief Returns the value of a symbol.
virtual uint32_t getSymbolValue(const std::string &name);
//! \brief Returns the size of a symbol.
virtual unsigned getSymbolSize(const std::string &name);
//@}
//! \name Direct ELF format access
//@{
//! \brief Returns the underlying StELFFile object.
StELFFile *getELFFile() { return m_file; }
//! \brief Gets information about a symbol in the ELF file.
bool lookupSymbol(const std::string &name, Elf32_Sym &info);
//@}
protected:
smart_ptr<StELFFile> m_file; //!< Parser for the ELF file.
elf_toolset_t m_toolset; //!< Toolset that produced the ELF file.
secinfo_clear_t m_secinfoOption; //!< How to deal with the .secinfo section. Ignored if the toolset is not GHS.
protected:
//! \brief Parses the toolset option value.
elf_toolset_t readToolsetOption();
//! \brief Reads the secinfoClear option.
secinfo_clear_t readSecinfoClearOption();
protected:
/*!
* \brief A data source with ELF file sections as the contents.
*
* Each segment of this data source corresponds directly with a named section
* of the ELF file it represents. When the data source is created, it contains
* no segments. Segments are created with the addSection() method, which takes
* the index of an ELF section and creates a corresponding segment.
*
* Two segment subclasses are used with this data source. The first, ProgBitsSegment,
* is used to represent sections whose type is #SHT_PROGBITS. These sections have
* binary data stored in the ELF file. The second segment type is NoBitsSegment.
* It is used to represent sections whose type is #SHT_NOBITS. These sections have
* no data, but simply allocate a region of memory to be filled with zeroes.
* As such, the NoBitsSegment class is a subclass of DataSource::PatternSegment.
*/
class ELFDataSource : public DataSource
{
public:
/*!
* \brief Represents one named #SHT_PROGBITS section within the ELF file.
*/
class ProgBitsSegment : public DataSource::Segment
{
public:
ProgBitsSegment(ELFDataSource &source, StELFFile *elf, unsigned index);
virtual unsigned getData(unsigned offset, unsigned maxBytes, uint8_t *buffer);
virtual unsigned getLength();
virtual bool hasNaturalLocation() { return true; }
virtual uint32_t getBaseAddress();
protected:
StELFFile *m_elf; //!< The format parser instance for this ELF file.
unsigned m_sectionIndex; //!< The index of the section this segment represents.
};
/*!
* \brief Represents one named #SHT_NOBITS section within the ELF file.
*
* This segment class is a subclass of DataSource::PatternSegment since it
* represents a region of memory to be filled with zeroes.
*/
class NoBitsSegment : public DataSource::PatternSegment
{
public:
NoBitsSegment(ELFDataSource &source, StELFFile *elf, unsigned index);
virtual unsigned getLength();
virtual bool hasNaturalLocation() { return true; }
virtual uint32_t getBaseAddress();
protected:
StELFFile *m_elf; //!< The format parser instance for this ELF file.
unsigned m_sectionIndex; //!< The index of the section this segment represents.
};
public:
//! \brief Default constructor.
ELFDataSource(StELFFile *elf)
: DataSource()
, m_elf(elf)
, m_secinfoOption(kSecinfoDefault)
{
}
//! \brief Destructor.
virtual ~ELFDataSource();
//! Set the option to control .secinfo usage.
inline void setSecinfoOption(secinfo_clear_t option) { m_secinfoOption = option; }
//! \brief Adds the ELF section at position \a sectionIndex to the data source.
void addSection(unsigned sectionIndex);
//! \brief Returns the number of segments in the source.
virtual unsigned getSegmentCount() { return (unsigned)m_segments.size(); }
//! \brief Returns the segment at position \a index.
virtual DataSource::Segment *getSegmentAt(unsigned index) { return m_segments[index]; }
protected:
StELFFile *m_elf; //!< The ELF file parser.
secinfo_clear_t m_secinfoOption; //!< How to deal with the .secinfo section. Ignored if the toolset is not GHS.
typedef std::vector<DataSource::Segment *> segment_vector_t; //!< A list of segment instances.
segment_vector_t m_segments; //!< The segments of this data source.
};
};
}; // namespace blfwk
#endif // _ELFSourceFile_h_

149
src/blfwk/EndianUtilities.h Normal file
View File

@ -0,0 +1,149 @@
/*
* Copyright (c) 2013-2014 Freescale Semiconductor, Inc.
* All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#if !defined(_EndianUtilities_h_)
#define _EndianUtilities_h_
//! \name Swap macros
//! These macros always swap the data.
//@{
//! Byte swap 16-bit value.
#define _BYTESWAP16(value) (((((uint16_t)value) << 8) & 0xFF00) | ((((uint16_t)value) >> 8) & 0x00FF))
//! Byte swap 32-bit value.
#define _BYTESWAP32(value) \
(((((uint32_t)value) << 24) & 0xFF000000) | ((((uint32_t)value) << 8) & 0x00FF0000) | \
((((uint32_t)value) >> 8) & 0x0000FF00) | ((((uint32_t)value) >> 24) & 0x000000FF))
//! Byte swap 64-bit value.
#define _BYTESWAP64(value) \
(((((uint64_t)value) << 56) & 0xFF00000000000000ULL) | ((((uint64_t)value) << 40) & 0x00FF000000000000ULL) | \
((((uint64_t)value) << 24) & 0x0000FF0000000000ULL) | ((((uint64_t)value) << 8) & 0x000000FF00000000ULL) | \
((((uint64_t)value) >> 8) & 0x00000000FF000000ULL) | ((((uint64_t)value) >> 24) & 0x0000000000FF0000ULL) | \
((((uint64_t)value) >> 40) & 0x000000000000FF00ULL) | ((((uint64_t)value) >> 56) & 0x00000000000000FFULL))
//@}
//! \name Inline swap functions
//@{
inline uint16_t _swap_u16(uint16_t value)
{
return _BYTESWAP16(value);
}
inline int16_t _swap_s16(int16_t value)
{
return (int16_t)_BYTESWAP16((uint16_t)value);
}
inline uint32_t _swap_u32(uint32_t value)
{
return _BYTESWAP32(value);
}
inline int32_t _swap_s32(int32_t value)
{
return (int32_t)_BYTESWAP32((uint32_t)value);
}
inline uint64_t _swap_u64(uint64_t value)
{
return _BYTESWAP64(value);
}
inline int64_t _swap_s64(int64_t value)
{
return (uint64_t)_BYTESWAP64((uint64_t)value);
}
//@}
#if defined(__LITTLE_ENDIAN__)
/* little endian host */
#define ENDIAN_BIG_TO_HOST_U16(value) (_swap_u16(value))
#define ENDIAN_HOST_TO_BIG_U16(value) (_swap_u16(value))
#define ENDIAN_BIG_TO_HOST_S16(value) (_swap_s16(value))
#define ENDIAN_HOST_TO_BIG_S16(value) (_swap_s16(value))
#define ENDIAN_BIG_TO_HOST_U32(value) (_swap_u32(value))
#define ENDIAN_HOST_TO_BIG_U32(value) (_swap_u32(value))
#define ENDIAN_BIG_TO_HOST_S32(value) (_swap_s32(value))
#define ENDIAN_HOST_TO_BIG_S32(value) (_swap_s32(value))
#define ENDIAN_BIG_TO_HOST_U64(value) (_swap_u64(value))
#define ENDIAN_HOST_TO_BIG_U64(value) (_swap_u64(value))
#define ENDIAN_BIG_TO_HOST_S64(value) (_swap_s64(value))
#define ENDIAN_HOST_TO_BIG_S64(value) (_swap_s64(value))
/* no-ops */
#define ENDIAN_LITTLE_TO_HOST_U16(value) (value)
#define ENDIAN_HOST_TO_LITTLE_U16(value) (value)
#define ENDIAN_LITTLE_TO_HOST_S16(value) (value)
#define ENDIAN_HOST_TO_LITTLE_S16(value) (value)
#define ENDIAN_LITTLE_TO_HOST_U32(value) (value)
#define ENDIAN_HOST_TO_LITTLE_U32(value) (value)
#define ENDIAN_LITTLE_TO_HOST_S32(value) (value)
#define ENDIAN_HOST_TO_LITTLE_S32(value) (value)
#define ENDIAN_LITTLE_TO_HOST_U64(value) (value)
#define ENDIAN_HOST_TO_LITTLE_U64(value) (value)
#define ENDIAN_LITTLE_TO_HOST_S64(value) (value)
#define ENDIAN_HOST_TO_LITTLE_S64(value) (value)
#elif defined(__BIG_ENDIAN__)
/* big endian host */
#define ENDIAN_LITTLE_TO_HOST_U16(value) (_swap_u16(value))
#define ENDIAN_HOST_TO_LITTLE_U16(value) (_swap_u16(value))
#define ENDIAN_LITTLE_TO_HOST_S16(value) (_swap_s16(value))
#define ENDIAN_HOST_TO_LITTLE_S16(value) (_swap_s16(value))
#define ENDIAN_LITTLE_TO_HOST_U32(value) (_swap_u32(value))
#define ENDIAN_HOST_TO_LITTLE_U32(value) (_swap_u32(value))
#define ENDIAN_LITTLE_TO_HOST_S32(value) (_swap_s32(value))
#define ENDIAN_HOST_TO_LITTLE_S32(value) (_swap_s32(value))
#define ENDIAN_LITTLE_TO_HOST_U64(value) (_swap_u64(value))
#define ENDIAN_HOST_TO_LITTLE_U64(value) (_swap_u64(value))
#define ENDIAN_LITTLE_TO_HOST_S64(value) (_swap_s64(value))
#define ENDIAN_HOST_TO_LITTLE_S64(value) (_swap_s64(value))
/* no-ops */
#define ENDIAN_BIG_TO_HOST_U16(value) (value)
#define ENDIAN_HOST_TO_BIG_U16(value) (value)
#define ENDIAN_BIG_TO_HOST_S16(value) (value)
#define ENDIAN_HOST_TO_BIG_S16(value) (value)
#define ENDIAN_BIG_TO_HOST_U32(value) (value)
#define ENDIAN_HOST_TO_BIG_U32(value) (value)
#define ENDIAN_BIG_TO_HOST_S32(value) (value)
#define ENDIAN_HOST_TO_BIG_S32(value) (value)
#define ENDIAN_BIG_TO_HOST_U64(value) (value)
#define ENDIAN_HOST_TO_BIG_U64(value) (value)
#define ENDIAN_BIG_TO_HOST_S64(value) (value)
#define ENDIAN_HOST_TO_BIG_S64(value) (value)
#endif
#endif // _EndianUtilities_h_

View File

@ -0,0 +1,68 @@
/*
* File: ExcludesListMatcher.h
*
* Copyright (c) 2015 Freescale Semiconductor, Inc.
* All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#if !defined(_ExcludesListMatcher_h_)
#define _ExcludesListMatcher_h_
#include "GlobMatcher.h"
#include <vector>
#include <string>
namespace blfwk
{
/*!
* \brief Matches strings using a series of include and exclude glob patterns.
*
* This string matcher class uses a sequential, ordered list of glob patterns to
* determine whether a string matches. Attached to each pattern is an include/exclude
* action. The patterns in the list effectively form a Boolean expression. Includes
* act as an OR operator while excludes act as an AND NOT operator.
*
* Examples (plus prefix is include, minus prefix is exclude):
* - +foo: foo
* - -foo: !foo
* - +foo, +bar: foo || bar
* - +foo, -bar: foo && !bar
* - +foo, -bar, +baz: foo && !bar || baz
*
* The only reason for inheriting from GlobMatcher is so we can access the protected
* globMatch() method.
*/
class ExcludesListMatcher : public GlobMatcher
{
public:
//! \brief Default constructor.
ExcludesListMatcher();
//! \brief Destructor.
~ExcludesListMatcher();
//! \name Pattern list
//@{
//! \brief Add one include or exclude pattern to the end of the match list.
void addPattern(bool isInclude, const std::string &pattern);
//@}
//! \brief Performs a single string match test against testValue.
virtual bool match(const std::string &testValue);
protected:
//! \brief Information about one glob pattern entry in a match list.
struct glob_list_item_t
{
bool m_isInclude; //!< True if include, false if exclude.
std::string m_glob; //!< The glob pattern to match.
};
typedef std::vector<glob_list_item_t> glob_list_t;
glob_list_t m_patterns; //!< Ordered list of include and exclude patterns.
};
}; // namespace blfwk
#endif // _ExcludesListMatcher_h_

70
src/blfwk/GHSSecInfo.h Normal file
View File

@ -0,0 +1,70 @@
/*
* Copyright (c) 2013-2014 Freescale Semiconductor, Inc.
* All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#if !defined(_GHSSecInfo_h_)
#define _GHSSecInfo_h_
#include "StELFFile.h"
#include "smart_ptr.h"
namespace blfwk
{
/*!
* \brief Wrapper around the GHS-specific .secinfo ELF section.
*
* ELF files produced by the Green Hills MULTI toolset will have a
* special .secinfo section. For the most part, this section contains
* a list of address
* ranges that should be filled by the C runtime startup code. The
* address ranges correspond to those of ELF sections whose type is
* #SHT_NOBITS. The GHS runtime uses this table instead of just filling
* all #SHT_NOBITS sections because the linker command file can
* be used to optionally not fill individual sections.
*
* The isSectionFilled() methods let calling code determine if an ELF
* section is found in the .secinfo table. If the section is found,
* then it should be filled.
*/
class GHSSecInfo
{
public:
//! \brief Default constructor.
GHSSecInfo(StELFFile *elf);
//! \brief Returns true if there is a .secinfo section present in the ELF file.
bool hasSecinfo() const { return m_hasInfo; }
//! \brief Determines if a section should be filled.
bool isSectionFilled(uint32_t addr, uint32_t length);
//! \brief Determines if \a section should be filled.
bool isSectionFilled(const Elf32_Shdr &section);
protected:
#pragma pack(1)
/*!
* \brief The structure of one .secinfo entry.
*/
struct ghs_secinfo_t
{
uint32_t m_clearAddr; //!< Address to start filling from.
uint32_t m_clearValue; //!< Value to fill with.
uint32_t m_numBytesToClear; //!< Number of bytes to fill.
};
#pragma pack()
protected:
StELFFile *m_elf; //!< The parser object for our ELF file.
bool m_hasInfo; //!< Whether .secinfo is present in the ELF file.
smart_array_ptr<ghs_secinfo_t>
m_info; //!< Pointer to the .secinfo entries. Will be NULL if there is no .secinfo section in the file.
unsigned m_entryCount; //!< Number of entries in #m_info.
};
}; // namespace blfwk
#endif // _GHSSecInfo_h_

61
src/blfwk/GlobMatcher.h Normal file
View File

@ -0,0 +1,61 @@
/*
* File: GlobMatcher.h
*
* Copyright (c) 2015 Freescale Semiconductor, Inc.
* All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#if !defined(_GlobMatcher_h_)
#define _GlobMatcher_h_
#include "StringMatcher.h"
namespace blfwk
{
/*!
* \brief This class uses glob pattern matching to match strings.
*
* Glob patterns:
* - * matches zero or more characters
* - ? matches any single character
* - [set] matches any character in the set
* - [^set] matches any character NOT in the set
* where a set is a group of characters or ranges. a range
* is written as two characters seperated with a hyphen: a-z denotes
* all characters between a to z inclusive.
* - [-set] set matches a literal hypen and any character in the set
* - []set] matches a literal close bracket and any character in the set
*
* - char matches itself except where char is '*' or '?' or '['
* - \\char matches char, including any pattern character
*
* Examples:
* - a*c ac abc abbc ...
* - a?c acc abc aXc ...
* - a[a-z]c aac abc acc ...
* - a[-a-z]c a-c aac abc ...
*/
class GlobMatcher : public StringMatcher
{
public:
//! \brief Constructor.
GlobMatcher(const std::string &pattern)
: StringMatcher()
, m_pattern(pattern)
{
}
//! \brief Returns whether \a testValue matches the glob pattern.
virtual bool match(const std::string &testValue);
protected:
std::string m_pattern; //!< The glob pattern to match against.
//! \brief Glob implementation.
bool globMatch(const char *str, const char *p);
};
}; // namespace blfwk
#endif // _GlobMatcher_h_

23
src/blfwk/HexValues.h Normal file
View File

@ -0,0 +1,23 @@
/*
* File: HexValues.h
*
* Copyright (c) 2015 Freescale Semiconductor, Inc.
* All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#if !defined(_HexValues_h_)
#define _HexValues_h_
#include <stdint.h>
//! \brief Determines whether \a c is a hex digit character.
bool isHexDigit(char c);
//! \brief Converts a hexidecimal character to the integer equivalent.
uint8_t hexCharToInt(char c);
//! \brief Converts a hex-encoded byte to the integer equivalent.
uint8_t hexByteToInt(const char *encodedByte);
#endif // _HexValues_h_

100
src/blfwk/I2cPeripheral.h Normal file
View File

@ -0,0 +1,100 @@
/*
* Copyright 2020 - 2022 NXP
* All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*
*/
#ifndef _i2c_peripheral_h_
#define _i2c_peripheral_h_
#include "Peripheral.h"
#include "blfwk/i2c.h"
#include "packet/command_packet.h"
//! @addtogroup i2c_peripheral
//! @{
namespace blfwk
{
/*!
* @brief Peripheral that talks to the target device over I2C port hardware.
*/
class I2cPeripheral : public Peripheral
{
public:
//! @breif Constants.
enum _i2c_peripheral_constants
{
// The read() implementation for the I2cPeripheral does not use this the timeout parameter.
kI2cPeripheral_UnusedTimeout = 0,
// Serial timeout is set to this default during init().
kI2cPeripheral_DefaultReadTimeoutMs = 10,
kI2cPeripheral_DefaultSpeedKHz = 100,
kI2cPeripheral_DefaultAddress = 0x10
};
public:
//! @brief Parameterized constructor that opens the serial port.
//!
//! Opens and configures the port. Throws exception if port configuration fails.
//!
//! @param port OS file path for I2C port. For example "/dev/i2c-0.0" on Linux.
//! @param speed Port speed, e.g. 9600.
//! @param address I2C slave's address
I2cPeripheral(const char *port,
long speed = kI2cPeripheral_DefaultSpeedKHz,
uint8_t address = kI2cPeripheral_DefaultAddress);
//! @brief Destructor.
virtual ~I2cPeripheral();
//! @brief Flush.
//!
//! should be called on an open I2C port in order to flush any remaining data in the I2C RX buffer
void flushRX();
//! @brief Read bytes.
//!
//! @param buffer Pointer to buffer.
//! @param requestedBytes Number of bytes to read.
//! @param actualBytes Number of bytes actually read.
//! @param timeoutMs Time in milliseconds to wait for read to complete.
virtual status_t read(uint8_t *buffer, uint32_t requestedBytes, uint32_t *actualBytes, uint32_t unused_timeoutMs);
//! @brief Write bytes.
//!
//! @param buffer Pointer to buffer to write
//! @param byteCount Number of bytes to write
virtual status_t write(const uint8_t *buffer, uint32_t byteCount);
//! @brief Return peripheral Type
virtual _host_peripheral_types get_type(void) { return kHostPeripheralType_I2C; }
protected:
//! @brief Initialize.
//!
//! Opens and configures the port.
//!
//! Note: following COM port configuration is assumed: 8 bits, 1 stop bit, no parity.
//!
//! @param port OS file path for I2C port. For example "/dev/i2c-0.0" on Linux.
//! @param speed Port speed, e.g. 9600.
//! @param address I2C slave's address
bool init(const char *port, long speed, uint8_t address);
int m_fileDescriptor; //!< Port file descriptor.
uint8_t m_buffer[kDefaultMaxPacketSize]; //!< Buffer for bytes used to build read packet.
uint32_t m_current_ReadTimeout; //!< The last value sent to serial_set_read_timeout().
};
} // namespace blfwk
//! @}
#endif // _i2c_peripheral_h_
////////////////////////////////////////////////////////////////////////////////
// EOF
////////////////////////////////////////////////////////////////////////////////

View File

@ -0,0 +1,78 @@
/*
* Copyright (c) 2013-2015 Freescale Semiconductor, Inc.
* All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#if !defined(_IntelHexSourceFile_h_)
#define _IntelHexSourceFile_h_
#include "SourceFile.h"
#include "StIntelHexFile.h"
#include "StExecutableImage.h"
namespace blfwk
{
/*!
* \brief Executable file in the Intel Hex format.
*
* Instead of presenting each Intel Hex in the file separately, this class
* builds up a memory image of all of the records. Records next to each other
* in memory are coalesced into a single memory region. The data source that
* is returned from createDataSource() exposes these regions as its segments.
*/
class IntelHexSourceFile : public SourceFile
{
public:
//! \brief Default constructor.
IntelHexSourceFile(const std::string &path);
//! \brief Destructor.
virtual ~IntelHexSourceFile() {}
//! \brief Test whether the \a stream contains a valid Intel Hex file.
static bool isIntelHexFile(std::istream &stream);
//! \name Opening and closing
//@{
//! \brief Opens the file.
virtual void open();
//! \brief Closes the file.
virtual void close();
//@}
//! \name Format capabilities
//@{
virtual bool supportsNamedSections() const { return false; }
virtual bool supportsNamedSymbols() const { return false; }
//@}
//! \name Data sources
//@{
//! \brief Returns data source for the entire file.
virtual DataSource *createDataSource();
//@}
//! \name Entry point
//@{
//! \brief Returns true if an entry point was set in the file.
virtual bool hasEntryPoint();
//! \brief Returns the entry point address.
virtual uint32_t getEntryPointAddress();
//@}
protected:
StIntelHexFile *m_file; //!< Intel Hex parser instance.
StExecutableImage *m_image; //!< Memory image of the Intel Hex file..
bool m_hasEntryRecord; //!< Whether a type 03 or 05 record was found.
StIntelHexFile::IntelHex m_entryRecord; //!< Record for the entry point.
protected:
//! \brief Build memory image of the Intel Hex file.
void buildMemoryImage();
};
}; // namespace blfwk
#endif // _IntelHexSourceFile_h_

261
src/blfwk/Logging.h Normal file
View File

@ -0,0 +1,261 @@
/*
* Copyright (c) 2013-2014 Freescale Semiconductor, Inc.
* All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#if !defined(_Logging_h_)
#define _Logging_h_
#include <string>
#include <assert.h>
#include <stdarg.h>
#include <fstream>
//! @addtogroup logging
//! @{
/*!
* \brief Base logger class.
*
* There are two types of logging levels that are used by this class. First
* there is the filter level. Any log message that is assigned a level
* higher than the current filter level is discarded. Secondly there is the
* current output level. Log messages that do not have their own level
* use the current output level to determine if they should be shown or
* not.
*
* The two methods setFilterLevel() and setOutputLevel() set the filter
* and default output logging levels, respectively. There are corresponding
* getter methods as well. Both the filter and output levels are
* initialized to #kInfo during object construction.
*
* Most use of the logger classes is expected to be through the Log
* class. It provides static logging methods that call through to a global
* singleton logger instance. There is also a Log::SetOutputLevel utility
* class that makes it extremely easiy to temporarily change the default
* output logging level.
*
* Of all the overloaded log() methods in this class, none of them are
* really expected to be reimplemented by subclasses. Instead, there is
* the single protected _log() method that takes a simple string pointer.
* The other log methods all wind up calling _log(), so it provides a
* single point to override. In fact, _log() is pure virtual, so subclasses
* must implement it.
*
* \see Log
*/
class Logger
{
public:
//! \brief Logging levels.
enum log_level_t
{
kUrgent = 0, //!< The lowest level, for messages that must always be logged.
kJson, //!< For machine language output only.
kError, //!< For fatal error messages.
kWarning, //!< For non-fatal warning messages.
kInfo, //!< The normal log level, for status messages.
kInfo2, //!< For verbose status messages.
kDebug, //!< For internal reporting.
kDebug2, //!< Highest log level; verbose debug logging.
kInfo1 = kInfo, //!< Alias for #kInfo
kDebug1 = kDebug //!< Alias for #kDebug
};
public:
//! \brief Default constructor.
Logger()
: m_filter(kInfo)
, m_level(kInfo)
{
}
//! \brief Destructor.
virtual ~Logger() {}
//! \name Logging levels
//@{
//! \brief Changes the logging level to \a level.
inline void setFilterLevel(log_level_t level) { m_filter = level; }
//! \brief Returns the current logging filter level.
inline log_level_t getFilterLevel() const { return m_filter; }
//! \brief Changes the logging output level to \a level.
inline void setOutputLevel(log_level_t level) { m_level = level; }
//! \brief Returns the current logging output level.
inline log_level_t getOutputLevel() const { return m_level; }
//@}
//! \name Logging
//@{
//! \brief Log with format.
virtual void log(const char *fmt, ...);
//! \brief Log a string object.
virtual void log(const std::string &msg) { log(msg.c_str()); }
//! \brief Log with format at a specific output level.
virtual void log(log_level_t level, const char *fmt, ...);
//! \brief Log a string output at a specific output level.
virtual void log(log_level_t level, const std::string &msg) { log(level, msg.c_str()); }
//! \brief Log with format using an argument list.
virtual void log(const char *fmt, va_list args);
//! \brief Log with format using an argument with a specific output level.
virtual void log(log_level_t level, const char *fmt, va_list args);
//@}
protected:
log_level_t m_filter; //!< The current logging filter level.
log_level_t m_level; //!< The current log output level.
protected:
//! \brief The base pure virtual logging function implemented by subclasses.
virtual void _log(const char *msg) = 0;
};
/*!
* \brief Wraps a set of static functions for easy global logging access.
*
* This class has a set of static methods that make it easy to access a global
* logger instance without having to worry about extern symbols. It does this
* by keeping a static member variable pointing at the singleton logger instance,
* which is set with the setLogger() static method.
*
* There is also an inner utility class called SetOutputLevel that uses
* C++ scoping rules to temporarily change the output logging level. When the
* SetOutputLevel instance falls out of scope the output level is restored
* to the previous value.
*/
class Log
{
public:
//! \name Singleton logger access
//@{
//! \brief Returns the current global logger singleton.
static inline Logger *getLogger() { return s_logger; }
//! \brief Sets the global logger singleton instance.
static inline void setLogger(Logger *logger) { s_logger = logger; }
//@}
//! \name Logging
//@{
//! \brief Log with format.
static void log(const char *fmt, ...);
//! \brief Log a string object.
static void log(const std::string &msg);
//! \brief Log with format at a specific output level.
static void log(Logger::log_level_t level, const char *fmt, ...);
//! \brief Log a string output at a specific output level.
static void log(Logger::log_level_t level, const std::string &msg);
//@}
//! @name Logging level helpers
//!
//! These static methods log a message with an implicit log level.
//@{
static void urgent(const char *fmt, ...); //!< Log a message with #Logger::kUrgent level.
static void json(const char *fmt, ...); //!< Log a message with #Logger::kJson level.
static void error(const char *fmt, ...); //!< Log a message with #Logger::kError level.
static void warning(const char *fmt, ...); //!< Log a message with #Logger::kWarning level.
static void info(const char *fmt, ...); //!< Log a message with #Logger::kInfo level.
static void info2(const char *fmt, ...); //!< Log a message with #Logger::kInfo2 level.
static void debug(const char *fmt, ...); //!< Log a message with #Logger::kDebug level.
static void debug2(const char *fmt, ...); //!< Log a message with #Logger::kDebug2 level.
//@}
protected:
static Logger *s_logger; //!< The single global logger instance.
public:
/*!
* \brief Utility class to temporarily change the logging output level.
*
* This class will change the current logging output level of a given
* logger instance. Then when it falls out of scope it will set the
* level back to what it was originally.
*
* Use like this:
* \code
* // output level is some value here
* {
* Log::SetOutputLevel leveler(Logger::DEBUG);
* // now output level is DEBUG
* Log::log("my debug message 1");
* Log::log("my debug message 2");
* }
* // output level is restored to previous value
* \endcode
*/
class SetOutputLevel
{
public:
//! \brief Default constructor.
//!
//! Saves the current logging output level of the global logger,
//! as managed by the Log class, and sets the new level to \a level.
SetOutputLevel(Logger::log_level_t level)
: m_logger(Log::getLogger())
, m_saved(Logger::kInfo)
{
assert(m_logger);
m_saved = m_logger->getOutputLevel();
m_logger->setOutputLevel(level);
}
//! \brief Constructor.
//!
//! Saves the current logging output level of \a logger and sets
//! the new level to \a level.
SetOutputLevel(Logger *logger, Logger::log_level_t level)
: m_logger(logger)
, m_saved(logger->getOutputLevel())
{
assert(m_logger);
m_logger->setOutputLevel(level);
}
//! \brief Destructor.
//!
//! Restores the saved logging output level.
~SetOutputLevel() { m_logger->setOutputLevel(m_saved); }
protected:
Logger *m_logger; //!< The logger instance we're controlling.
Logger::log_level_t m_saved; //!< Original logging output level.
};
};
/*!
* \brief Simple logger that writes to stdout.
*/
class StdoutLogger : public Logger
{
protected:
//! \brief Logs the message to stdout.
virtual void _log(const char *msg);
};
/*!
* \brief Simple logger that writes to a file.
*/
class FileLogger : public Logger
{
public:
FileLogger(const char *file_path);
~FileLogger();
protected:
//! \brief Logs the message to the file.
virtual void _log(const char *msg);
//! \brief The name of the file, including the path, to log to.
const std::string m_file_path;
//! \brief The name of the file, including the path, to log to.
std::ofstream m_logFile;
};
//! @}
#endif // _Logging_h_

232
src/blfwk/LpcUsbSio.h Normal file
View File

@ -0,0 +1,232 @@
/*
* Copyright 2020 - 2022 NXP
* All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*
*/
#ifndef _LpcUsbSio_h_
#define _LpcUsbSio_h_
#include <string.h>
#include "host_types.h"
#include "middleware/libusbsio/inc/lpcusbsio.h"
//! @addtogroup lpc_usb_sio
//! @{
namespace blfwk
{
/*!
* @brief Interface with the LPC USB Serial I/O
*/
class LpcUsbSio
{
public:
//! @brief Constants
enum _lpc_usb_sio_port_contants
{
kDefault_Vid = LPCUSBSIO_VID, //!< NXP VID
kDefault_Pid = LPCUSBSIO_PID, //!< PID for LPC USB Serial I/O
};
enum _lpc_usb_sio_timeout_contants
{
kDefault_TimeoutMs = LPCUSBSIO_READ_TMO, //!< 500ms, timeout miliseconds for reading
};
enum lpc_usb_sio_function_t
{
kFunction_None,
kFunction_SPI,
kFunction_I2C,
kFunction_GPIO,
};
//! @brief SPI clock polarity configuration.
enum spi_clock_polarity_t
{
kSpiPolarity_ActiveHigh = 0, //!< Active-high SPI clock (idles low).
kSpiPolarity_ActiveLow = 1 //!< Active-low SPI clock (idles high).
};
//! @brief SPI clock phase configuration.
enum spi_clock_phase_t
{
kSpiPhase_FirstEdge = 0, //!< First edge on SPSCK occurs at the middle of the first cycle of a data transfer.
kSpiPhase_SecondEdge = 1 //!< First edge on SPSCK occurs at the start of the first cycle of a data transfer.
};
//! @brief I2C slave address
enum i2c_slave_address_t
{
kI2cAddress_Default = 0x10, //!< Default I2C slave address.
};
//! @brief LPC USB Serial I/O USB port configuration.
struct LpcUsbSioPortConfigData
{
uint16_t usbVid;
uint16_t usbPid;
std::string usbString;
std::string usbPath;
int32_t portIndex;
LpcUsbSioPortConfigData()
{
usbVid = LpcUsbSio::kDefault_Vid;
usbPid = LpcUsbSio::kDefault_Pid;
portIndex = 0;
}
};
//! @brief LPC USB Serial I/O SPI configuration.
struct LpcUsbSioSpiConfigData
{
uint32_t spiSpeedHz;
spi_clock_polarity_t spiPolarity;
spi_clock_phase_t spiPhase;
uint8_t spiSselPort;
uint8_t spiSselPin;
int32_t spiPortIndex;
LpcUsbSioSpiConfigData()
{
spiSpeedHz = 100000;
spiPolarity = LpcUsbSio::kSpiPolarity_ActiveLow;
spiPhase = LpcUsbSio::kSpiPhase_SecondEdge;
spiSselPort = 0;
spiSselPin = 0;
spiPortIndex = 0;
}
};
//! @brief LPC USB Serial I/O I2C configuration.
struct LpcUsbSioI2cConfigData
{
uint8_t i2cAddress;
I2C_CLOCKRATE_T i2cSpeedHz;
int32_t i2cPortIndex;
LpcUsbSioI2cConfigData()
{
i2cAddress = LpcUsbSio::kI2cAddress_Default;
i2cSpeedHz = I2C_CLOCK_STANDARD_MODE;
i2cPortIndex = 0;
}
};
//! @brief LPC USB Serial I/O GPIO configuration.
struct LpcUsbSioGpioConfigData
{
uint8_t gpioPort;
uint8_t gpioPin;
uint8_t gpioValue;
uint8_t gpioMode;
int32_t gpioPortIndex;
LpcUsbSioGpioConfigData()
{
gpioPort = 0;
gpioPin = 0;
gpioValue = 0;
gpioMode = 0;
gpioPortIndex = 0;
}
};
//! @brief LPC USB Serial I/O configuration data.
struct LpcUsbSioConfigData
{
lpc_usb_sio_function_t function;
LpcUsbSioPortConfigData portConfig;
LpcUsbSioSpiConfigData spiConfig;
LpcUsbSioI2cConfigData i2cConfig;
LpcUsbSioConfigData() { function = LpcUsbSio::kFunction_None; }
};
//! @brief Constructor.
LpcUsbSio(const LpcUsbSio::LpcUsbSioPortConfigData &config);
//! @brief Destructor.
virtual ~LpcUsbSio();
//! @brief Parse the params in options into the config structure.
static bool parse(const string_vector_t &params, LpcUsbSio::LpcUsbSioConfigData &config);
//! @brief Convert LPC USB Serial I/O error code to detail string.
static const std::string getError(LPCUSBSIO_ERR_T errorCode);
//! @brief Write data.
virtual uint32_t write(const uint8_t *data, uint32_t byteCount) = 0;
//! @brief Read data.
virtual uint32_t read(uint8_t *data, uint32_t byteCount) = 0;
protected:
uint16_t m_usbVid; //!< The VID of LPC USB Serial I/O.
uint16_t m_usbPid; //!< The PID of LPC USB Serial I/O.
std::string m_usbString; //!< The USB Serial String of LPC USB Serial I/O port.
std::string m_usbPath; //!< The USB instance path of LPC USB Serial I/O port.
int32_t m_portCount; //!< The number of LPC USB Serial I/O connected.
int32_t m_portIndex; //!< The port of LPC USB Serial I/O which is active. Index starts from 0.
LPC_HANDLE m_portHandler; //!< The LPC USB Serial I/O hardware operation handler.
};
class LpcUsbSioSpi : public LpcUsbSio
{
public:
//! @brief Constructor.
LpcUsbSioSpi(const LpcUsbSio::LpcUsbSioPortConfigData &portConfig,
const LpcUsbSio::LpcUsbSioSpiConfigData &spiConfig);
//! @brief Destructor.
virtual ~LpcUsbSioSpi();
//! @brief Write data.
virtual uint32_t write(const uint8_t *data, uint32_t byteCount);
//! @brief Read data.
virtual uint32_t read(uint8_t *data, uint32_t byteCount);
protected:
int32_t m_spiPortCount; //!< The number of SPI port on current LPC USB Serial I/O.
int32_t m_spiPortIndex; //!< The port of SPI which is active. Index starts from 0.
uint8_t m_spiSselPort; //!< The port numer of the SPI->SSELn pin on LPC USB Serial I/O.
uint8_t m_spiSselPin; //!< The pin number of the SPI->SSELn pin on LPC USB Serial I/O.
LPC_HANDLE m_spiPortHandler; //!< The SPI operation handler.
};
class LpcUsbSioI2c : public LpcUsbSio
{
public:
//! @brief Constructor.
LpcUsbSioI2c(const LpcUsbSio::LpcUsbSioPortConfigData &portConfig,
const LpcUsbSio::LpcUsbSioI2cConfigData &i2cConfig);
//! @brief Destructor.
virtual ~LpcUsbSioI2c();
//! @brief Write data.
virtual uint32_t write(const uint8_t *data, uint32_t byteCount);
//! @brief Read data.
virtual uint32_t read(uint8_t *data, uint32_t byteCount);
protected:
int32_t m_i2cPortCount; //!< The number of I2C port on current LPC USB Serial I/O.
int32_t m_i2cPortIndex; //!< The port of I2C which is active. Index starts from 0.
LPC_HANDLE m_i2cPortHandler; //!< The I2C operation handler.
uint8_t m_i2cAddress; //!< The I2C slave address to communicate.
};
} // namespace blfwk
//! @}
#endif // _LpcUsbSio_h_
////////////////////////////////////////////////////////////////////////////////
// EOF
////////////////////////////////////////////////////////////////////////////////

View File

@ -0,0 +1,63 @@
/*
* Copyright 2020 - 2022 NXP
* All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*
*/
#ifndef _LpcUsbSioPeripheral_h_
#define _LpcUsbSioPeripheral_h_
#include "Peripheral.h"
//! @addtogroup lpc_usb_sio_peripheral
//! @{
namespace blfwk
{
/*!
* @brief Peripheral that talks to the target device over LPCUSB Serial I/O hardware.
*/
class LpcUsbSioPeripheral : public Peripheral
{
public:
//! @brief Parameterized constructor that opens the LPC USB Serial I/O port.
//!
//! Opens and configures the port. Throws exception if operation fails.
//!
//! @param config The configuration data of LPCUSB Serial I/O device.
LpcUsbSioPeripheral(const LpcUsbSio::LpcUsbSioConfigData &config);
//! @brief Destructor.
virtual ~LpcUsbSioPeripheral();
//! @brief Read bytes.
//!
//! @param buffer Pointer to buffer
//! @param requestedBytes Number of bytes to read
//! @param actualBytes Number of bytes got
//! @param timeoutMs The timeout microseconds for the read operation
virtual status_t read(uint8_t *buffer, uint32_t requestedBytes, uint32_t *actualBytes, uint32_t timeoutMs);
//! @brief Write bytes.
//!
//! @param buffer Pointer to buffer to write
//! @param byteCount Number of bytes to write
virtual status_t write(const uint8_t *buffer, uint32_t byteCount);
//! @brief Get the peripheral type.
virtual _host_peripheral_types get_type(void) { return kHostPeripheralType_LPCUSBSIO; }
protected:
LpcUsbSio *m_lpcUsbSio; //!< Represents LPC USB Serial I/O hardware.
};
} // namespace blfwk
//! @}
#endif // _LpcUsbSioPeripheral_h_
////////////////////////////////////////////////////////////////////////////////
// EOF
////////////////////////////////////////////////////////////////////////////////

51
src/blfwk/OptionContext.h Normal file
View File

@ -0,0 +1,51 @@
/*
* Copyright (c) 2013-2014 Freescale Semiconductor, Inc.
* All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#if !defined(_OptionContext_h_)
#define _OptionContext_h_
#include <string>
#include "Value.h"
namespace blfwk
{
/*!
* \brief Pure abstract interface class to a table of options.
*/
class OptionContext
{
public:
//! @brief Force a virtual destructor.
virtual ~OptionContext() {}
//! \brief Detemine whether the named option is present in the table.
//! \param name The name of the option to query.
//! \retval true The option is present and has a value.
//! \retval false No option with that name is in the table.
virtual bool hasOption(const std::string &name) const = 0;
//! \brief Returns the option's value.
//! \param name The name of the option.
//! \return The value for the option named \a name.
//! \retval NULL No option is in the table with that name.
virtual const Value *getOption(const std::string &name) const = 0;
//! \brief Adds or changes an option's value.
//!
//! If the option was not already present in the table, it is added.
//! Otherwise the old value is replaced.
//!
//! \param name The option's name.
//! \param value New value for the option.
virtual void setOption(const std::string &name, Value *value) = 0;
//! \brief Removes an option from the table.
//! \param name The name of the option to remove.
virtual void deleteOption(const std::string &name) = 0;
};
}; // namespace blfwk
#endif // _OptionContext_h_

109
src/blfwk/Packetizer.h Normal file
View File

@ -0,0 +1,109 @@
/*
* Copyright (c) 2013-2014 Freescale Semiconductor, Inc.
* All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef _Packetizer_h_
#define _Packetizer_h_
#include "bootloader_common.h"
#include "bootloader/bl_peripheral.h"
#include <time.h>
//! @addtogroup host_packetizers
//! @{
namespace blfwk
{
// Forward declarations.
class Peripheral;
//! @brief Packetizer status codes.
enum _packetizer_status
{
kStatus_NoPingResponse = MAKE_STATUS(kStatusGroup_Packetizer, 0),
kStatus_InvalidPacketType = MAKE_STATUS(kStatusGroup_Packetizer, 1),
kStatus_InvalidCRC = MAKE_STATUS(kStatusGroup_Packetizer, 2),
kStatus_NoCommandResponse = MAKE_STATUS(kStatusGroup_Packetizer, 3)
};
/*!
* @brief Interface class for packetization of commands and data.
*/
class Packetizer
{
public:
Packetizer(Peripheral *peripheral, uint32_t packetTimeoutMs)
: m_peripheral(peripheral)
, m_packetTimeoutMs(packetTimeoutMs)
, m_version()
, m_options(0)
, m_isAbortEnabled(false)
, m_readCount(0)
{
}
virtual ~Packetizer(){};
//! @brief Read a packet.
virtual status_t readPacket(uint8_t **packet, uint32_t *packetLength, packet_type_t packetType) = 0;
//! @brief Write a packet.
virtual status_t writePacket(const uint8_t *packet, uint32_t byteCount, packet_type_t packetType) = 0;
//! @brief Abort data phase.
virtual void abortPacket() = 0;
//! @brief Send framing packet ack.
virtual void sync() = 0;
//! @brief Finalize.
virtual void finalize() = 0;
//! @brief Enable simulator command processor pump.
virtual void enableSimulatorPump() = 0;
//! @brief Pump simulator command processor.
virtual void pumpSimulator() = 0;
//! @brief Set aborted flag.
//!
//! Used for out-of-band flow control for simulator.
virtual void setAborted(bool aborted) = 0;
//! @brief Return the max packet size.
virtual uint32_t getMaxPacketSize() = 0;
//! @brieif Optional control of number of bytes requested from peripheral by readPacket().
virtual void setReadCount(uint32_t byteCount) { m_readCount = byteCount; }
//! @brief Peripheral accessor.
virtual Peripheral *getPeripheral() { return m_peripheral; }
//! @brief Get Framing Protocol Version
standard_version_t getVersion() { return m_version; }
//! @brief Get Framing Protocol Options
uint16_t getOptions() { return m_options; }
//! @brief Set abort packet check enable.
void setAbortEnabled(bool isEnabled) { m_isAbortEnabled = isEnabled; }
//! @biref Check if abort data phase is enabled.
bool isAbortEnabled() { return m_isAbortEnabled; }
protected:
Peripheral *m_peripheral; //!< Peripheral to send/receive bytes on.
standard_version_t m_version; //!< Framing protocol version.
uint16_t m_options; //!< Framing protocol options bitfield.
uint32_t m_packetTimeoutMs;
bool m_isAbortEnabled; //!< True if allowing abort packet. Not used by all packetizers.
uint32_t m_readCount; //!< Optional control of number of bytes requested by readPacket().
};
} // namespace blfwk
//! @}
#endif // _Packetizer_h_
////////////////////////////////////////////////////////////////////////////////
// EOF
////////////////////////////////////////////////////////////////////////////////

88
src/blfwk/Peripheral.h Normal file
View File

@ -0,0 +1,88 @@
/*
* Copyright (c) 2013-2014 Freescale Semiconductor, Inc.
* Copyright 2020 - 2022 NXP
* All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef _Peripheral_h_
#define _Peripheral_h_
#include <string.h>
#include "BusPal.h"
#include "LpcUsbSio.h"
#include "bootloader_common.h"
//! @addtogroup host_peripherals
//! @{
namespace blfwk
{
/*!
* @brief Represents a peripheral.
*
* Interface class for objects that provide the source for commands or sink for responses.
*/
class Peripheral
{
public:
enum _host_peripheral_types
{
kHostPeripheralType_None,
kHostPeripheralType_UART,
kHostPeripheralType_BUSPAL_UART,
kHostPeripheralType_LPCUSBSIO,
kHostPeripheralType_USB_HID,
kHostPeripheralType_SIM,
kHostPeripheralType_I2C,
kHostPeripheralType_SPI,
};
struct PeripheralConfigData
{
_host_peripheral_types peripheralType;
bool ping;
std::string comPortName;
long comPortSpeed;
uint32_t packetTimeoutMs;
unsigned short usbHidVid;
unsigned short usbHidPid;
std::string usbHidSerialNumber;
std::string usbPath;
#if defined(LINUX) && defined(__ARM__)
unsigned char i2cAddress;
unsigned char spiPolarity;
unsigned char spiPhase;
unsigned char spiSequence;
#endif // #if defined(LINUX) && defined(__ARM__)
BusPal::BusPalConfigData busPalConfig;
LpcUsbSio::LpcUsbSioConfigData lpcUsbSioConfig;
};
virtual ~Peripheral(){};
//! @brief Read bytes.
//!
//! @param buffer Pointer to buffer
//! @param requestedBytes Number of bytes to read
//! @param timeoutMs Time in milliseconds to wait for read to complete.
//! @param actualBytes Number of bytes actually read.
virtual status_t read(uint8_t *buffer, uint32_t requestedBytes, uint32_t *actualBytes, uint32_t timeout) = 0;
//! @brief Write bytes.
virtual status_t write(const uint8_t *buffer, uint32_t byteCount) = 0;
//! @brief Return peripheral Type
virtual _host_peripheral_types get_type(void) = 0;
};
} // namespace blfwk
//! @}
#endif // _Peripheral_h_
////////////////////////////////////////////////////////////////////////////////
// EOF
////////////////////////////////////////////////////////////////////////////////

86
src/blfwk/Progress.h Normal file
View File

@ -0,0 +1,86 @@
/*
* Copyright (c) 2015 Freescale Semiconductor, Inc.
* All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef _Progress_h_
#define _Progress_h_
#pragma once
#include "blfwk/host_types.h"
/*!
* @brief Contains the callback function for progress and abort phase.
*
*/
class Progress
{
public:
//! @brief Default constructor.
Progress()
: m_segmentIndex(1)
, m_segmentCount(1)
, m_progressCallback(NULL)
, m_abortPhase(NULL)
{
}
//! @brief Constructor with initial callback.
Progress(void(*callback)(int, int, int), bool *abortPhase)
: m_segmentIndex(1)
, m_segmentCount(1)
, m_progressCallback(callback)
, m_abortPhase(abortPhase)
{
}
//! @brief Default destructor.
~Progress() {}
//! @brief execute the progress callback function.
//!
//! @param percentage the percentage of current executed progress.
void progressCallback(int percentage)
{
if (m_progressCallback != NULL)
{
m_progressCallback(percentage, m_segmentIndex, m_segmentCount);
}
}
//! @brief Check whether the data phase is canceled.
bool abortPhase(void)
{
if ((m_abortPhase) && (*m_abortPhase == true))
{
return true;
}
else
{
return false;
}
}
//! @biref initialized the progress callback function and the variable of controlling data phase.
//!
//! @param callback The progress callback function.
//!
//! @param abortPhase The pointer pointing to a variable controlling whether abort current data phase.
void registerCallback(void(*callback)(int, int, int), bool *abortPhase)
{
m_progressCallback = callback;
m_abortPhase = abortPhase;
}
public:
int m_segmentIndex; //!< Index of data segment in progressing.
int m_segmentCount; //!< The number of data segments.
private:
void(*m_progressCallback)(int percentage, int segmentIndex, int segmentCount); //!< The progress callback function.
bool *m_abortPhase; //!< The pointer pointing to a variable controlling whether abort current data phase.
};
#endif // _Progress_h_

58
src/blfwk/Random.h Normal file
View File

@ -0,0 +1,58 @@
/*
* File: Random.h
*
* Copyright (c) 2015 Freescale Semiconductor, Inc.
* All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#if !defined(_Random_h_)
#define _Random_h_
#include "stdafx.h"
#ifdef WIN32
/*!
* This class is from the crypto++ library.
*/
class MicrosoftCryptoProvider
{
public:
MicrosoftCryptoProvider();
~MicrosoftCryptoProvider();
#if defined(_WIN64)
typedef unsigned __int64 ProviderHandle; // type HCRYPTPROV, avoid #include <windows.h>
#else
typedef unsigned long ProviderHandle;
#endif
ProviderHandle GetProviderHandle() const { return m_hProvider; }
private:
ProviderHandle m_hProvider;
};
#pragma comment(lib, "advapi32.lib")
#endif // WIN32
/*!
* Encapsulates the Windows CryptoAPI's CryptGenRandom or /dev/urandom on Unix systems.
*/
class RandomNumberGenerator
{
public:
RandomNumberGenerator();
~RandomNumberGenerator();
uint8_t generateByte();
void generateBlock(uint8_t *output, unsigned count);
protected:
#ifdef WIN32
#ifndef WORKAROUND_MS_BUG_Q258000
MicrosoftCryptoProvider m_provider;
#endif
#else // WIN32
int m_fd;
#endif // WIN32
};
#endif // _Random_h_

62
src/blfwk/RijndaelCTR.h Normal file
View File

@ -0,0 +1,62 @@
/*
* File: RijndaelCTR.h
*
* Copyright (c) 2015 Freescale Semiconductor, Inc.
* All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#if !defined(_RijndaelCTR_h_)
#define _RijndaelCTR_h_
#include "AESKey.h"
#include "AESCounter.h"
#include <string.h>
/*!
* \brief Class to compute AES 128 CTR encryption/decryption.
*
* Currently only supports 128-bit keys and block sizes.
*/
class RijndaelCTR
{
public:
enum
{
BLOCK_SIZE = 16 //!< Number of bytes in one cipher block.
};
//! The cipher block data type.
typedef uint8_t block_t[BLOCK_SIZE];
public:
//! \brief Constructor.
RijndaelCTR(const AESKey<128> &key, const AESCounter<128> &counter);
//! \brief Encrypt data.
void encrypt(const uint8_t *data, unsigned length, uint8_t *dest);
//! \brief Encrypt data.
void decrypt(const uint8_t *data, unsigned length, uint8_t *dest);
//! \brief Assignment operator.
RijndaelCTR &operator=(const RijndaelCTR &other)
{
m_key = other.m_key;
m_counter = other.m_counter;
return *this;
}
protected:
AESKey<128> m_key; //!< 128-bit key to use for encrypt/decrypt
AESCounter<128> m_counter; //!< Counter value for encrypt/decrypt
void incrementCounter(AESCounter<128>::counter_t *counter);
void baseProcess(const uint8_t *data, unsigned length, uint8_t *dest);
private:
//! \brief inaccessible default constructor.
RijndaelCTR() {}
};
#endif // _RijndaelCTR_h_

135
src/blfwk/SBSourceFile.h Normal file
View File

@ -0,0 +1,135 @@
/*
* Copyright (c) 2013-2014 Freescale Semiconductor, Inc.
* All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#if !defined(_SBSourceFile_h_)
#define _SBSourceFile_h_
#include "blfwk/SourceFile.h"
#include "blfwk/StELFFile.h"
#include "blfwk/smart_ptr.h"
#include "blfwk/DataSource.h"
#include "blfwk/DataTarget.h"
namespace blfwk
{
/*!
* \brief SB Format (SB) source file.
*/
class SBSourceFile : public BinarySourceFile
{
public:
//! \brief Default constructor.
SBSourceFile(const std::string &path);
//! \brief Destructor.
virtual ~SBSourceFile();
//! \brief Identifies whether the stream contains an SB file.
static bool isSBFile(std::istream &stream);
//! \name Data source creation
//@{
//! \brief Creates an unmapped data source from the entire file.
virtual DataSource *createDataSource();
//@}
protected:
//! An AES-128 cipher block is 16 bytes.
typedef uint8_t cipher_block_t[16];
//! A SHA-1 digest is 160 bits, or 20 bytes.
typedef uint8_t sha1_digest_t[20];
//! Unique identifier type for a section.
typedef uint32_t section_id_t;
// All of these structures are packed to byte alignment in order to match
// the structure on disk.
#pragma pack(1)
//! Same version struct used for 3600 boot image.
struct version_t
{
uint16_t m_major;
uint16_t m_pad0;
uint16_t m_minor;
uint16_t m_pad1;
uint16_t m_revision;
uint16_t m_pad2;
};
//! \brief Header for the entire boot image.
//!
//! Fields of this header are arranged so that those used by the bootloader ROM all come
//! first. They are also set up so that all fields are not split across cipher block
//! boundaries. The fields not used by the bootloader are not subject to this
//! restraint.
//!
//! Image header size is always a round number of cipher blocks. The same also applies to
//! the boot image itself. The padding, held in #blfwk::EncoreBootImage::boot_image_header_t::m_padding0
//! and #blfwk::EncoreBootImage::boot_image_header_t::m_padding1 is filled with random bytes.
//!
//! The DEK dictionary, section table, and each section data region must all start on
//! cipher block boundaries.
//!
//! This header is not encrypted in the image file.
//!
//! The m_digest field contains a SHA-1 digest of the fields of the header that follow it.
//! It is the first field in the header so it doesn't change position or split the header
//! in two if fields are added to the header.
struct boot_image_header_t
{
union
{
sha1_digest_t m_digest; //!< SHA-1 digest of image header. Also used as the crypto IV.
struct
{
cipher_block_t m_iv; //!< The first 16 bytes of the digest form the initialization vector.
uint8_t m_extra[4]; //!< The leftover top four bytes of the SHA-1 digest.
};
};
uint8_t m_signature[4]; //!< 'STMP', see #ROM_IMAGE_HEADER_SIGNATURE.
uint8_t m_majorVersion; //!< Major version for the image format, see #ROM_BOOT_IMAGE_MAJOR_VERSION.
uint8_t m_minorVersion; //!< Minor version of the boot image format, see #ROM_BOOT_IMAGE_MINOR_VERSION.
uint16_t m_flags; //!< Flags or options associated with the entire image.
uint32_t m_imageBlocks; //!< Size of entire image in blocks.
uint32_t m_firstBootTagBlock; //!< Offset from start of file to the first boot tag, in blocks.
section_id_t m_firstBootableSectionID; //!< ID of section to start booting from.
uint16_t m_keyCount; //!< Number of entries in DEK dictionary.
uint16_t m_keyDictionaryBlock; //!< Starting block number for the key dictionary.
uint16_t m_headerBlocks; //!< Size of this header, including this size word, in blocks.
uint16_t m_sectionCount; //!< Number of section headers in this table.
uint16_t m_sectionHeaderSize; //!< Size in blocks of a section header.
uint8_t m_padding0[2]; //!< Padding to align #m_timestamp to long word.
uint8_t m_signature2[4]; //!< Second signature to distinguish this .sb format from the 36xx format, see
//!#ROM_IMAGE_HEADER_SIGNATURE2.
uint64_t m_timestamp; //!< Timestamp when image was generated in microseconds since 1-1-2000.
version_t m_productVersion; //!< Product version.
version_t m_componentVersion; //!< Component version.
uint16_t m_driveTag; //!< Drive tag for the system drive which this boot image belongs to.
uint8_t m_padding1[6]; //!< Padding to round up to next cipher block.
};
#pragma pack()
public:
/*!
* \brief Simple exception thrown to indicate an error in the input SB file format.
*/
class SBFileException : public std::runtime_error
{
public:
//! \brief Default constructor.
SBFileException(const std::string &inMessage)
: std::runtime_error(inMessage)
{
}
};
};
}; // namespace blfwk
#endif // _SBSourceFile_h_

387
src/blfwk/SDPCommand.h Normal file
View File

@ -0,0 +1,387 @@
/*
* Copyright (c) 2015 Freescale Semiconductor, Inc.
* Copyright 2016-2018 NXP
* All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef _SDPCommand_h_
#define _SDPCommand_h_
#pragma once
#include "host_types.h"
#include "Progress.h"
#include "Packetizer.h"
//! @addtogroup sdp_commands
//! @{
using namespace std;
namespace blfwk
{
//! @brief SDP Command structure.
struct sdp_cmd_t
{
uint16_t cmdType;
const char *const name;
sdp_cmd_t(uint16_t cmdType, const char *name)
: cmdType(cmdType)
, name(name)
{
}
};
//! @name SDP command types and names.
//@{
const sdp_cmd_t kSDPCommand_ReadRegister(0x0101, "read-register");
const sdp_cmd_t kSDPCommand_WriteRegister(0x0202, "write-register");
const sdp_cmd_t kSDPCommand_WriteFile(0x0404, "write-file");
const sdp_cmd_t kSDPCommand_ErrorStatus(0x0505, "error-status");
const sdp_cmd_t kSDPCommand_DcdWrite(0x0a0a, "dcd-write");
const sdp_cmd_t kSDPCommand_SkipDcdHeader(0x0c0c, "skip-dcd-header");
const sdp_cmd_t kSDPCommand_JumpAddress(0x0b0b, "jump-address");
const sdp_cmd_t kSDPCommand_SetBaudrate(0x0d0d, "set-baudrate");
const sdp_cmd_t kSDPCommand_Ping(0x5aa6, "ping");
//@}
/*!
* @brief Represents an SDP command.
*
* Do not instantiate this class. Instead, use the create() method to
* create the appropriate subclass based on command name in argv[0].
*/
class SDPCommand
{
public:
//! @brief Constants
enum _constants
{
kCmdSizeBytes = 16, //!< Number of bytes in SDP command.
kHabModeSizeBytes = 4, //!< Number of bytes in HAB mode response.
kResponseSizeBytes = 64, //!< Number of bytes in status response.
kSendDataSizeBytes = 1024, //!< Number of bytes in data packet.
kMaxDcdSizeBytes = 1024, //!< Max number bytes in DCD table.
kHabEnabled = 0x12343412, //!< HAB mode enabled.
kHabDisabled = 0x56787856, //!< HAB mode disabled.
kWriteComplete = 0x128a8a12, //!< Write Complete status response.
kWriteFileComplete = 0x88888888, //!< Write File Complete status response.
kHabStatusFailure = 0x33333333, //!< HAB failed response.
kHabStatusWarning = 0x69696969, //!< HAB wrarning response.
kHabStatusSuccess = 0xf0f0f0f0, //!< HAB success resopnse.
kReEnum_Ack = 0x89232389, //!< Return Error Number Ack
kStatus_NoResponse = 10004, //!< Matches Bootloader kStatusNoResponse.
kOk_Ack = 0x900DD009, //!< Response to skip-dcd-header command.
};
public:
//! @brief Create an appropriate command subclass.
//!
//! Pass the command name in argv[0] and optional
//! arguments in the rest of the string vector.
//! Caller is responsible for deleting the returned object.
//!
//! @param argv Argument vector
//! @retval Command object
static SDPCommand *create(const string_vector_t *argv);
protected:
//! @brief Constructor that takes a command name and list of arguments.
//!
//! @param argv Argument vector
SDPCommand(const string_vector_t *argv)
: m_argv(*argv)
, m_progress()
, m_responseValues()
, m_cmdBuf()
{
}
public:
//! @brief Destructor.
virtual ~SDPCommand() {}
//! @brief Initialize.
//!
//! Subclasses should implement init() to check for valid arguments.
virtual bool init() { return true; }
//! @name String arguments accessors.
//@{
//! @brief Get the specified argument.
virtual std::string getArg(int arg) const { return m_argv.at(arg); }
//! @brief Get the command name (i.e. argv[0]).
virtual std::string getName() const { return getArg(0); }
//! @brief Get the number of arguments, including the command name.
virtual size_t getArgCount() const { return m_argv.size(); }
//@}
//! @brief Send command to packetizer and on to peripheral.
virtual void sendTo(Packetizer &packetizer) {}
//! @brief Get response values vector.
virtual const uint32_vector_t *getResponseValues() const
{
return const_cast<uint32_vector_t *>(&m_responseValues);
}
//! @brief Get response as JSON string.
virtual std::string getResponse() const;
//! @brief Log the response description.
virtual void logResponses() const;
//! @brief Register an object for displaying transfer progress.
virtual void registerProgress(Progress *progress) { m_progress = progress; }
protected:
//! @brief Create packed buffer with SDP command.
void packCommand(uint16_t cmdType, uint32_t address, uint32_t format, uint32_t dataCount, uint32_t data);
//! @brief Send command to packetizer.
status_t sendCommand(Packetizer &packetizer);
//! @brief Send command and read HAB mode response.
status_t sendCommandGetHabMode(Packetizer &packetizer);
//! @brief Read response value from device.
//!
//! Use kPacketTypeData for 64-byte read-register response, kPacketTypeCommand for 4-byte status response and HAB
//! mode response.
uint8_t *getStatusResponse(Packetizer &packetizer, packet_type_t type = kPacketType_Command);
//! @brief Read HAB mode response from device.
bool isHabModeValid(Packetizer &packetizer);
protected:
string_vector_t m_argv; //!< Vector of argument strings.
Progress *m_progress; //!< Variable for progress control.
uint32_vector_t m_responseValues; //!< Vector of response values.
uint8_t m_cmdBuf[kCmdSizeBytes]; //!< Buffer for command bytes.
};
/*!
* @brief Represents the SDP ReadRegister command.
*
*/
class SDPReadRegister : public SDPCommand
{
public:
//! @brief Constructor that takes argument vector.
SDPReadRegister(const string_vector_t *argv)
: SDPCommand(argv)
, m_address(0)
, m_format(32)
, m_dataCount(4)
, m_file()
{
}
//! @brief Initialize.
virtual bool init();
//! @brief Send command to packetizer.
virtual void sendTo(Packetizer &packetizer);
protected:
uint32_t m_address; //!< Target memory address.
uint32_t m_format; //!< Register format.
uint32_t m_dataCount; //!< Number of bytes to read.
std::string m_file; //!< Data file path.
};
/*!
* @brief Represents the SDP WriteRegister command.
*
*/
class SDPWriteRegister : public SDPCommand
{
public:
//! @brief Constructor that takes argument vector.
SDPWriteRegister(const string_vector_t *argv)
: SDPCommand(argv)
, m_address(0)
, m_format(32)
, m_data(0)
{
}
//! @brief Initialize.
virtual bool init();
//! @brief Send command to packetizer.
virtual void sendTo(Packetizer &packetizer);
protected:
uint32_t m_address; //!< Target memory address.
uint32_t m_format; //!< Register format.
uint32_t m_data; //!< Data value to write.
};
/*!
* @brief Represents the SDP WriteFile command.
*
*/
class SDPWriteFile : public SDPCommand
{
public:
//! @brief Constructor that takes argument vector.
SDPWriteFile(const string_vector_t *argv)
: SDPCommand(argv)
, m_address(0)
, m_file()
, m_dataCount(0)
{
}
//! @brief Initialize.
virtual bool init();
//! @brief Send command to packetizer.
virtual void sendTo(Packetizer &packetizer);
protected:
uint32_t m_address; //!< Target memory address.
std::string m_file; //!< Data file path.
uint32_t m_dataCount; //!< Number of bytes to write.
};
/*!
* @brief Represents the SDP ErrorStatus command.
*
*/
class SDPErrorStatus : public SDPCommand
{
public:
//! @brief Constructor that takes argument vector.
SDPErrorStatus(const string_vector_t *argv)
: SDPCommand(argv)
{
}
//! @brief Initialize.
virtual bool init();
//! @brief Send command to packetizer.
virtual void sendTo(Packetizer &packetizer);
};
/*!
* @brief Represents the SDP DcdWrite command.
*
*/
class SDPDcdWrite : public SDPCommand
{
public:
//! @brief Constructor that takes argument vector.
SDPDcdWrite(const string_vector_t *argv)
: SDPCommand(argv)
, m_address(0)
, m_file()
{
}
//! @brief Initialize.
virtual bool init();
//! @brief Send command to packetizer.
virtual void sendTo(Packetizer &packetizer);
protected:
uint32_t m_address; //!< Temporary storage address.
std::string m_file; //!< Data file path.
};
/*!
* @brief Represents the SDP SkipDcdHeader command.
*
*/
class SDPSkipDcdHeader : public SDPCommand
{
public:
//! @brief Constructor that takes argument vector.
SDPSkipDcdHeader(const string_vector_t *argv)
: SDPCommand(argv)
{
}
//! @brief Initialize.
virtual bool init();
//! @brief Send command to packetizer.
virtual void sendTo(Packetizer &packetizer);
};
/*!
* @brief Represents the SDP JumpAddress command.
*
*/
class SDPJumpAddress : public SDPCommand
{
public:
//! @brief Constructor that takes argument vector.
SDPJumpAddress(const string_vector_t *argv)
: SDPCommand(argv)
, m_address(0)
{
}
//! @brief Initialize.
virtual bool init();
//! @brief Send command to packetizer.
virtual void sendTo(Packetizer &packetizer);
protected:
uint32_t m_address; //!< Target memory address.
};
/*!
* @brief REpresents the SDP SetBaudrate command.
*
*/
class SDPSetBaudrate : public SDPCommand
{
public:
//! @brief Constructor that takes argument vector.
SDPSetBaudrate(const string_vector_t *argv)
: SDPCommand(argv)
, m_baudrate(115200)
{
}
//! @brief Initialize.
virtual bool init();
//! @brief Send command to packetizer.
virtual void sendTo(Packetizer &packetizer);
protected:
uint32_t m_baudrate; //!< Baudrate
};
/*!
* @brief Represents the SDP SkipDcdHeader command.
*
*/
class SDPPing : public SDPCommand
{
public:
//! @brief Constructor that takes argument vector.
SDPPing(const string_vector_t *argv)
: SDPCommand(argv)
{
}
//! @brief Initialize.
virtual bool init();
//! @brief Send command to packetizer.
virtual void sendTo(Packetizer &packetizer);
};
} // namespace blfwk
//! @}
#endif // _SDPCommand_h_

View File

@ -0,0 +1,108 @@
/*
* Copyright (c) 2015 Freescale Semiconductor, Inc.
* All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef _sdp_uart_packetizer_h_
#define _sdp_uart_packetizer_h_
#include "Packetizer.h"
#include "UartPeripheral.h"
#include "serial.h"
#pragma once
//! @addtogroup sdp_uart_packetizer
//! @{
namespace blfwk
{
/*!
* @brief Provides source and sink for SDP packets that go over UART.
*/
class SDPUartPacketizer : public Packetizer
{
public:
//! @brief Constants.
enum _constants
{
kMaxReadSizeBytes = 64, //!< Max bytes returned by single read.
kNumBytesCommandResponse = 4, //!< Number of bytes in a kPacketTypeCommand read.
};
public:
//! @brief Default Constructor.
SDPUartPacketizer(UartPeripheral *peripheral, uint32_t readPacketTimeoutMs)
: Packetizer(peripheral, readPacketTimeoutMs)
, m_readBuf()
{
}
//! @brief Destructor.
virtual ~SDPUartPacketizer() {}
//! @brief Read a packet.
//!
//! Provides the address of a buffer containing the packet.
//!
//! @param packet Pointer location to write packet pointer
//! @param packetLength Number of bytes in returned packet
virtual status_t readPacket(uint8_t **packet, uint32_t *packetLength, packet_type_t packetType)
{
uint32_t count = ((packetType == kPacketType_Command) || (m_readCount == 0)) ? kNumBytesCommandResponse : m_readCount;
if (count > sizeof(m_readBuf))
{
count = sizeof(m_readBuf);
}
status_t status = getPeripheral()->read(m_readBuf, count, packetLength, m_packetTimeoutMs);
*packet = m_readBuf;
return status;
}
//! @brief Write a packet.
//!
//! @param packet Pointer to packet to write
//! @param byteCount Number of bytes in packet
virtual status_t writePacket(const uint8_t *packet, uint32_t byteCount, packet_type_t packetType)
{
return getPeripheral()->write(packet, byteCount);
}
//! @brief Finalize.
virtual void finalize() {};
//! @brief Peripheral accessor.
virtual UartPeripheral *getPeripheral() { return (UartPeripheral *)m_peripheral; }
//! @brief Abort data phase.
virtual void abortPacket() {};
//! @brief Send framing packet ack.
virtual void sync() {};
//! @brief Enable simulator command processor pump.
virtual void enableSimulatorPump() {};
//! @brief Pump simulator command processor.
virtual void pumpSimulator() {};
//! @brief Set aborted flag.
//!
//! Used for out-of-band flow control for simulator.
virtual void setAborted(bool aborted) {};
//! @brief Return the max packet size.
virtual uint32_t getMaxPacketSize() { return 0; }
protected:
uint8_t m_readBuf[kMaxReadSizeBytes]; //!< Buffer for read data.
};
} // namespace blfwk
//! @}
#endif // _sdp_uart_packetizer_h_

View File

@ -0,0 +1,106 @@
/*
* Copyright (c) 2015 Freescale Semiconductor, Inc.
* All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef _sdp_usb_hid_packetizer_h_
#define _sdp_usb_hid_packetizer_h_
#include "Packetizer.h"
#include "UsbHidPeripheral.h"
#include "hidapi.h"
#pragma once
//! @addtogroup sdp_usb_hid_packetizer
//! @{
namespace blfwk
{
/*!
* @brief Provides source and sink for SDP packets that go over USB HID class.
*/
class SDPUsbHidPacketizer : public Packetizer
{
public:
//! @brief Constants
enum _usbhid_constants
{
kMaxReportSizeBytes = 1024 + 1, //!< Number of bytes in largest report, including report type byte.
kIdReport1 = 1, //!< Code for report ID 1.
kReport1SizeBytes = 16 + 1, //!< Number of bytes in report 1, including report type byte.
kIdReport2 = 2, //!< Code for report ID 2.
kReport2SizeBytes = 1024 + 1, //!< Number of bytes in report 2, including report type byte.
kIdReport3 = 3, //!< Code for report ID 3.
#if defined(WIN32)
kReport3SizeBytes = 64 + 1, //!< Number of bytes in report 3, including report type byte.
#elif defined(LINUX) || defined(MACOSX)
kReport3SizeBytes = 4 + 1, //!< Number of bytes in report 3, including report type byte.
#endif
kIdReport4 = 4, //!< Code for report ID 4.
kReport4SizeBytes = 64 + 1, //!< Number of bytes in report 4, including report type byte.
kPollPacketMaxRetryCnt = 50, //!< Number of read retries.
};
public:
//! @brief Default Constructor.
SDPUsbHidPacketizer(UsbHidPeripheral *peripheral, uint32_t readPacketTimeoutMs)
: Packetizer(peripheral, readPacketTimeoutMs)
{
}
//! @brief Destructor.
virtual ~SDPUsbHidPacketizer() {}
//! @brief Read a packet.
//!
//! Provides the address of a buffer containing the packet.
//!
//! @param packet Pointer location to write packet pointer
//! @param packetLength Number of bytes in returned packet
virtual status_t readPacket(uint8_t **packet, uint32_t *packetLength, packet_type_t packetType);
//! @brief Write a packet.
//!
//! @param packet Pointer to packet to write
//! @param byteCount Number of bytes in packet
virtual status_t writePacket(const uint8_t *packet, uint32_t byteCount, packet_type_t packetType);
//! @brief Finalize.
virtual void finalize() {};
//! @brief Peripheral accessor.
virtual UsbHidPeripheral *getPeripheral() { return (UsbHidPeripheral *)m_peripheral; }
//! @brief Abort data phase.
virtual void abortPacket() {};
//! @brief Send framing packet ack.
virtual void sync() {};
//! @brief Enable simulator command processor pump.
virtual void enableSimulatorPump() {};
//! @brief Pump simulator command processor.
virtual void pumpSimulator() {};
//! @brief Set aborted flag.
//!
//! Used for out-of-band flow control for simulator.
virtual void setAborted(bool aborted) {};
//! @brief Return the max packet size.
virtual uint32_t getMaxPacketSize() { return 0; }
protected:
uint8_t m_report[kMaxReportSizeBytes]; //!< Buffer for report bytes.
};
} // namespace blfwk
//! @}
#endif // _sdp_usb_hid_packetizer_h_

View File

@ -0,0 +1,81 @@
/*
* Copyright (c) 2013-2014 Freescale Semiconductor, Inc.
* All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#if !defined(_SRecordSourceFile_h_)
#define _SRecordSourceFile_h_
#include "SourceFile.h"
#include "StSRecordFile.h"
#include "StExecutableImage.h"
namespace blfwk
{
/*!
* \brief Executable file in the Motorola S-record format.
*
* Instead of presenting each S-record in the file separately, this class
* builds up a memory image of all of the records. Records next to each other
* in memory are coalesced into a single memory region. The data source that
* is returned from createDataSource() exposes these regions as its segments.
*
* Because the S-record format does not support the concepts, no support is
* provided for named sections or symbols.
*/
class SRecordSourceFile : public SourceFile
{
public:
//! \brief Default constructor.
SRecordSourceFile(const std::string &path);
//! \brief Destructor.
virtual ~SRecordSourceFile() {}
//! \brief Test whether the \a stream contains a valid S-record file.
static bool isSRecordFile(std::istream &stream);
//! \name Opening and closing
//@{
//! \brief Opens the file.
virtual void open();
//! \brief Closes the file.
virtual void close();
//@}
//! \name Format capabilities
//@{
virtual bool supportsNamedSections() const { return false; }
virtual bool supportsNamedSymbols() const { return false; }
//@}
//! \name Data sources
//@{
//! \brief Returns data source for the entire file.
virtual DataSource *createDataSource();
//@}
//! \name Entry point
//@{
//! \brief Returns true if an entry point was set in the file.
virtual bool hasEntryPoint();
//! \brief Returns the entry point address.
virtual uint32_t getEntryPointAddress();
//@}
protected:
StSRecordFile *m_file; //!< S-record parser instance.
StExecutableImage *m_image; //!< Memory image of the S-record file.
bool m_hasEntryRecord; //!< Whether an S7,8,9 record was found.
StSRecordFile::SRecord m_entryRecord; //!< Record for the entry point.
protected:
//! \brief Build memory image of the S-record file.
void buildMemoryImage();
};
}; // namespace blfwk
#endif // _SRecordSourceFile_h_

57
src/blfwk/SearchPath.h Normal file
View File

@ -0,0 +1,57 @@
/*
* Copyright (c) 2013-2014 Freescale Semiconductor, Inc.
* All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#if !defined(_searchpath_h_)
#define _searchpath_h_
#include <string>
#include <list>
/*!
* \brief Handles searching a list of paths for a file.
*/
class PathSearcher
{
public:
//!
enum _target_type
{
kFindFile,
kFindDirectory
};
//!
typedef enum _target_type target_type_t;
protected:
//! Global search object singleton.
static PathSearcher *s_searcher;
public:
//! \brief Access global path searching object.
static PathSearcher &getGlobalSearcher();
public:
//! \brief Constructor.
PathSearcher() {}
//! \brief Add a new search path to the end of the list.
void addSearchPath(std::string &path);
//! \brief Attempts to locate a file by using the search paths.
bool search(const std::string &base, target_type_t targetType, bool searchCwd, std::string &result);
protected:
typedef std::list<std::string> string_list_t; //!< Linked list of strings.
string_list_t m_paths; //!< Ordered list of paths to search.
//! \brief Returns whether \a path is absolute.
bool isAbsolute(const std::string &path);
//! \brief Combines two paths into a single one.
std::string joinPaths(const std::string &first, const std::string &second);
};
#endif // _searchpath_h_

View File

@ -0,0 +1,147 @@
/*
* Copyright (c) 2013-2014 Freescale Semiconductor, Inc.
* All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef _serial_packetizer_h_
#define _serial_packetizer_h_
#include "Packetizer.h"
#include "UartPeripheral.h"
#include "bootloader_common.h"
#include "packet/serial_packet.h"
//! @addtogroup serial_packetizer
//! @{
namespace blfwk
{
// Forward declarations.
class Peripheral;
/*!
* @brief Provides source and sink for packets that go over the serial peripherals.
*/
class SerialPacketizer : public Packetizer
{
public:
//! @brief Constructor.
SerialPacketizer(Peripheral *peripheral, uint32_t packetTimeoutMs);
//! @brief Destructor.
virtual ~SerialPacketizer();
//! @brief Peripheral accessor.
virtual UartPeripheral *getPeripheral() { return dynamic_cast<UartPeripheral *>(m_peripheral); }
//! @brief Read a packet.
//!
//! Provides the address of a buffer containing the packet.
//!
//! @param packet Pointer location to write packet pointer
//! @param packetLength Number of bytes in returned packet.
virtual status_t readPacket(uint8_t **packet, uint32_t *packetLength, packet_type_t packetType);
//! @brief Write a packet.
//!
//! @param packet Pointer to packet to write.
//! @param byteCount Number of bytes in packet.
virtual status_t writePacket(const uint8_t *packet, uint32_t byteCount, packet_type_t packetType);
//! @brief Abort data phase.
virtual void abortPacket();
//! @brief Send framing packet ack.
virtual void sync();
//! @brief Finalize.
virtual void finalize();
//! @brief Enable simulator command processor pump.
virtual void enableSimulatorPump() {}
//! @brief Pump simulator command processor.
virtual void pumpSimulator() {}
//! @brief Set aborted flag.
virtual void setAborted(bool aborted) {}
//! @brief Return the max packet size.
virtual uint32_t getMaxPacketSize();
//! @brief Delay milliseconds.
void host_delay(uint32_t milliseconds);
//! @brief Send a ping packet and receive an ack.
//!
//! This is a method for host only side pinging of the target. The reponse from the
//! target to a ping packet is a ping response packet. Since the target may or may
//! not be online there is optionally a series of retries to make the best attempt
//! at communication possible
//!
//! @param retries The number of attempts that should be made.
//! @param delay The time in milliseconds between each attempt.
//! @param comSpeed The peripheral baud rate. Used in order to calculate the
//! receive delay in the case of low com speeds such as 100 and 300 which need
//! nearly a second to complete
virtual status_t ping(
int retries, unsigned int delay, ping_response_t *response, int comSpeed, int *actualComSpeed);
protected:
//! @brief Send ACK if needed.
status_t send_deferred_ack();
//! @brief Read packet using serial framing.
//!
//! On return, caller must call flow control method to send AckContinue or AckWait followed by Continue.
status_t serial_packet_read(uint8_t **packet, uint32_t *packetLength, packet_type_t packetType);
//! @brief Write packet using serial framing.
status_t serial_packet_write(const uint8_t *packet, uint32_t byteCount, packet_type_t packetType);
//! @brief Abort data phase.
//!
//! Respond to next host data packet with AckAbort instead of Ack
//! (i.e. receiver data phase abort).
void serial_packet_abort();
//! @brief Get max packet size.
uint32_t serial_packet_get_max_packet_size();
//! @brief Send a sync packet of the specified type.
status_t serial_packet_send_sync(uint8_t framingPacketType);
//! @brief Send a ping message back in response to a ping.
status_t serial_send_ping_response();
//! @brief Wait for an ACK, handling NAKs as needed.
status_t wait_for_ack_packet();
//! @brief Read from peripheral until entire data framing packet read.
status_t read_data_packet(framing_data_packet_t *packet, uint8_t *data, packet_type_t packetType);
//! @brief Read from peripheral until start byte found.
status_t read_start_byte(framing_header_t *header);
//! @brief Read from peripheral until packet header found.
status_t read_header(framing_header_t *header);
//! @brief Read from peripheral until packet length found.
status_t read_length(framing_data_packet_t *packet);
//! @brief Read from peripheral until crc16 is found.
status_t read_crc16(framing_data_packet_t *packet);
//! @brief Calculate crc over framing data packet.
uint16_t calculate_framing_crc16(framing_data_packet_t *packet, const uint8_t *data);
serial_data_t m_serialContext;
};
} // namespace blfwk
//! @}
#endif // _serial_packetizer_h_
////////////////////////////////////////////////////////////////////////////////
// EOF
////////////////////////////////////////////////////////////////////////////////

86
src/blfwk/SimPacketizer.h Normal file
View File

@ -0,0 +1,86 @@
/*
* Copyright (c) 2013-2014 Freescale Semiconductor, Inc.
* All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef _sim_packetizer_h_
#define _sim_packetizer_h_
#include "Packetizer.h"
#include "SimPeripheral.h"
#include "packet/command_packet.h"
namespace blfwk
{
// Forward declarations.
class Peripheral;
/*!
* @brief Provides source and sink for packets in the simulator space.
*/
class SimPacketizer : public Packetizer
{
public:
//! @brief Constants
enum _simPacketizer_contants
{
kSimReadTimeoutMs = 5000
};
public:
//! @brief Default Constructor.
SimPacketizer(SimPeripheral *peripheral);
//! @brief Destructor.
virtual ~SimPacketizer();
//! @brief Peripheral accessor.
virtual SimPeripheral *getPeripheral() { return dynamic_cast<SimPeripheral *>(m_peripheral); }
//! @brief Read a packet.
//!
//! Provides the address of a buffer containing the packet.
//!
//! @param packet Pointer location to write packet pointer
//! @param packetLength Number of bytes in returned packet.
virtual status_t readPacket(uint8_t **packet, uint32_t *packetLength, packet_type_t packetType);
//! @brief Write a packet.
//!
//! @param packet Pointer to packet to write.
//! @param byteCount Number of bytes in packet.
virtual status_t writePacket(const uint8_t *packet, uint32_t byteCount, packet_type_t packetType);
//! @brief Abort data phase.
virtual void abortPacket() { setAborted(true); }
//! @brief Send framing packet ack.
virtual void sync(){};
//! @brief Finalize.
virtual void finalize();
//! @brief Enable simulator command processor pump.
virtual void enableSimulatorPump() { m_isPumpEnabled = true; }
//! @brief Pump simulator command processor.
virtual void pumpSimulator();
//! @brief Set aborted flag.
//!
//! Used for out-of-band flow control for simulator.
virtual void setAborted(bool aborted) { m_isAborted = aborted; }
//! @brief Return the max packet size.
virtual uint32_t getMaxPacketSize() { return kDefaultMaxPacketSize; }
protected:
bool m_isPumpEnabled; //!< True if simulator pump enabled.
bool m_isAborted; //!< Data phase abort requested by receiver.
uint8_t m_buffer[kDefaultMaxPacketSize]; //!< Buffer for bytes used to build read packet.
};
} // namespace blfwk
#endif // _sim_packetizer_h_
////////////////////////////////////////////////////////////////////////////////
// EOF
////////////////////////////////////////////////////////////////////////////////

57
src/blfwk/SimPeripheral.h Normal file
View File

@ -0,0 +1,57 @@
/*
* Copyright (c) 2013-2014 Freescale Semiconductor, Inc.
* All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef _sim_peripheral_h_
#define _sim_peripheral_h_
#include "blfwk/Peripheral.h"
namespace blfwk
{
/*!
* @brief Peripheral that operates in the simulation space.
*
* Simulation peripherals are connected together using the streams provided to the init() method.
* For example, to connect a "host" peripheral to a "device" peripheral, specify the host's output
* stream as the device's input stream.
*/
class SimPeripheral : public Peripheral
{
public:
//! @brief Default Constructor.
SimPeripheral(uchar_deque_t *inStream, uchar_deque_t *outStream)
: m_inStream(inStream)
, m_outStream(outStream)
{
}
//! @brief Read bytes.
//!
//! @param buffer Pointer to buffer.
//! @param requestedBytes Number of bytes to read.
//! @param actualBytes Number of bytes actually read.
//! @param timeoutMs Time in milliseconds to wait for read to complete.
virtual status_t read(uint8_t *buffer, uint32_t requestedBytes, uint32_t *actualBytes, uint32_t timeoutMs);
//! @brief Write bytes.
//!
//! @param buffer Pointer to buffer to write
//! @param byteCount Number of bytes to write
virtual status_t write(const uint8_t *buffer, uint32_t byteCount);
protected:
uchar_deque_t *m_inStream; //!< Writes go to this stream.
uchar_deque_t *m_outStream; //!< Reads come from this stream.
};
} // namespace blfwk
#endif // _sim_peripheral_h_
////////////////////////////////////////////////////////////////////////////////
// EOF
////////////////////////////////////////////////////////////////////////////////

91
src/blfwk/Simulator.h Normal file
View File

@ -0,0 +1,91 @@
/*
* Copyright (c) 2013-2014 Freescale Semiconductor, Inc.
* All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef _Simulator_h_
#define _Simulator_h_
#include "Bootloader.h"
#include "Command.h"
#include "SimulatorMemory.h"
#include "SimPacketizer.h"
#include "Peripheral.h"
#include "Logging.h"
#include "bootloader/bl_command.h"
#include "bootloader/bl_context.h"
namespace blfwk
{
/*!
* @brief Represents the host bootloader.
*
* This class provides a convenient way to access other bootloader
* framework objects.
*/
class Simulator : public Bootloader
{
public:
//! @brief A vector of memory stores.
typedef std::vector<blfwk::MemoryStore *> memory_vector_t;
//! @brief Get the singleton simulator object.
static Simulator &getSimulator()
{
//! @brief Singleton object.
static Simulator theSimulator;
return theSimulator;
}
//! @brief Destructor.
virtual ~Simulator();
//! @brief Initialize.
void init();
//! @brief Configure and open state files.
//!
//! Must be called to open or create state files.
//!
//! @param pathToDir Directory for state files.
//! @param forceCreate True to re-create state files even if they exist.
bool openStateFiles(const std::string &pathToDir, bool forceCreate);
//! @name Accessors.
//@{
//! @brief Get the host packetizer.
SimPacketizer *getHost() const { return dynamic_cast<SimPacketizer *>(m_hostPacketizer); }
//! @brief Get the device packetizer.
SimPacketizer *getDevice() const { return m_devicePacketizer; }
//! @brief Get a device state memory store.
//!
//! index Index into memory map for the simulated device.
MemoryStore *getMemoryStore(int index) const { return m_memoryStore[index]; }
//@}
protected:
//! @brief Constructor.
Simulator();
SimPacketizer *m_devicePacketizer; //!< Packet interface to recieve commands on.
uchar_deque_t m_commandStream;
uchar_deque_t m_responseStream;
command_processor_data_t m_commandProcessor;
bool m_areStateFilesOpen; //!< True if state files are in use
memory_vector_t m_memoryStore; //!< Vector of memory stores, one per map entry.
OptionsStore m_optionsStore; //!< Persistent options store.
property_store_t m_propertyStore;
peripheral_descriptor_t m_activePeripheral; //!< Descriptor for the active peripheral.
FileLogger *m_logger; //!< Singleton logger instance.
};
} // namespace blfwk
#endif // _Simulator_h_
////////////////////////////////////////////////////////////////////////////////
// EOF
////////////////////////////////////////////////////////////////////////////////

271
src/blfwk/SimulatorMemory.h Normal file
View File

@ -0,0 +1,271 @@
/*
* Copyright (c) 2013-2014 Freescale Semiconductor, Inc.
* All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef _Memory_h_
#define _Memory_h_
#include "blfwk/host_types.h"
namespace blfwk
{
/*!
* @brief Represents target device memory as a disk file.
*/
class MemoryStore
{
public:
//! @brief Map indicies.
enum
{
kMapIndexFlash = 0, //!< Flash memory
kMapIndexSRAM = 1 //!< SRAM
};
public:
//! @brief Constructor that takes a map index.
//!
//! @param mapIndex Index into memory map array
//! @param fillByte Optional byte erase value, default 0
MemoryStore(int mapIndex, uint32_t fillByte = 0)
: m_mapIndex(mapIndex)
, m_fillByte(fillByte)
, m_size(0)
, m_startAddress(0)
, m_memoryFile(NULL)
{
}
//! @brief Open the store.
//!
//! @param pathToDir Directory for memory backing file.
//! @param forceCreate True to re-create backing file even if it exists.
bool open(const std::string &pathToDir, bool forceCreate);
//! @brief Close the store.
void close()
{
if (m_memoryFile)
{
fclose(m_memoryFile);
m_memoryFile = NULL;
}
}
//! @brief Read from memory.
//!
//! The requested offset is adjusted by the store's start address to create a zero-based
//! file offset.
//!
//! @param offset Offset into memory region
//! @param size Number of bytes to read
//! @param buffer Destination buffer
//! @return Number of bytes read
size_t read(long int offset, size_t size, unsigned char *buffer);
//! @brief Write to memory.
//!
//! The requested offset is adjusted by the store's start address to create a zero-based
//! file offset.
//!
//! @param offset Offset into memory region
//! @param size Number of bytes to write
//! @param buffer Source buffer
//! @return Number of bytes written
size_t write(long int offset, size_t size, const unsigned char *buffer);
//! @brief Erase memory.
//!
//! The requested offset is adjusted by the store's start address to create a zero-based
//! file offset.
//!
//! @param offset Offset into memory region
//! @param size Number of bytes to erase
void erase(long int offset, size_t size);
//! @brief Erase all memory.
void erase() { erase(0, m_size); }
protected:
int m_mapIndex; //!< Index of memory map entry.
uint8_t m_fillByte; //!< Erase value.
size_t m_size; //!< Size of memory file.
uint32_t m_startAddress; //!< Address address from map.
FILE *m_memoryFile; //!< Handle to memory file.
};
/*!
* @brief Represents target Flash memory.
*/
class FlashMemoryStore : public MemoryStore
{
public:
//! @brief Default Constructor.
FlashMemoryStore()
: MemoryStore(MemoryStore::kMapIndexFlash, ~0)
{
}
};
/*!
* @brief Represents target SRAM memory.
*/
class SramMemoryStore : public MemoryStore
{
public:
//! @brief Default Constructor.
SramMemoryStore()
: MemoryStore(MemoryStore::kMapIndexSRAM)
{
}
};
/*!
* @brief Holds persistent options.
*/
class OptionsStore
{
public:
//! @brief Constructor.
OptionsStore()
: m_optionsFile()
{
}
//! @brief Initialize the store.
//!
//! @param pathToDir Directory for options file.
//! @param forceCreate True to re-create options file even if it exists.
bool init(const std::string &pathToDir, bool forceCreate);
//! @brief Persist the store.
void persist();
//! @name Accessors.
//@{
//! @todo get/set for property store values
//@}
protected:
std::string m_optionsFile; //!< Options file name.
};
} // namespace blfwk
////////////////////////////////////////////////////////////////////////////////
// Prototypes
////////////////////////////////////////////////////////////////////////////////
#if defined(__cplusplus)
extern "C" {
#endif // __cplusplus
//! @brief Read from simulated flash memory.
//!
//! @param address Simulated address.
//! @param length Number of bytes to read.
//! @param buffer Destination buffer.
//!
//! @retval kStatusMemoryReadFailed
//! @retval kStatus_Success
status_t sim_flash_read(uint32_t address, uint32_t length, uint8_t *buffer);
//! @brief Write to simulated flash memory.
//!
//! @param address Simulated address.
//! @param length Number of bytes to write.
//! @param buffer Source buffer.
//!
//! @retval kStatusMemoryWriteFailed
//! @retval kStatus_Success
status_t sim_flash_write(uint32_t address, uint32_t length, const uint8_t *buffer);
//! @brief Fill simulated flash memory.
//!
//! @param address Simulated address.
//! @param length Number of bytes to write.
//! @param pattern 4-byte pattern.
//!
//! @retval kStatusMemoryWriteFailed
//! @retval kStatus_Success
status_t sim_flash_fill(uint32_t address, uint32_t length, uint32_t pattern);
//! @brief Erase simulated flash memory.
//!
//! @param address Simulated address.
//! @param length Number of bytes to write.
//!
//! @retval kStatusMemoryWriteFailed
//! @retval kStatus_Success
status_t sim_flash_erase(uint32_t address, uint32_t length);
//! @brief Erase all simulated flash memory.
//!
//! @retval kStatusMemoryWriteFailed
//! @retval kStatus_Success
status_t sim_flash_erase_all(void);
//! @brief Read from simulated SRAM memory.
//!
//! @param address Simulated address.
//! @param length Number of bytes to read.
//! @param buffer Destination buffer.
//!
//! @retval kStatusMemoryReadFailed
//! @retval kStatus_Success
status_t sim_sram_mem_read(uint32_t address, uint32_t length, uint8_t *buffer);
//! @brief Write to simulated SRAM memory.
//!
//! @param address Simulated address.
//! @param length Number of bytes to write.
//! @param buffer Source buffer.
//!
//! @retval kStatusMemoryWriteFailed
//! @retval kStatus_Success
status_t sim_sram_mem_write(uint32_t address, uint32_t length, const uint8_t *buffer);
//! @brief Fill simulated SRAM memory.
//!
//! @param address Simulated address.
//! @param length Number of bytes to write.
//! @param pattern 4-byte pattern.
//!
//! @retval kStatusMemoryWriteFailed
//! @retval kStatus_Success
status_t sim_sram_mem_fill(uint32_t address, uint32_t length, uint32_t pattern);
//! Read from simulated device memory.
//!
//! Not supported.
//!
//! @retval kStatus_Success;
status_t sim_device_mem_read(uint32_t address, uint32_t length, uint8_t *buffer);
//! Write to simulated device memory.
//!
//! Not supported.
//!
//! @retval kStatus_Success;
status_t sim_device_mem_write(uint32_t address, uint32_t length, const uint8_t *buffer);
//! Fill simulated device memory.
//!
//! Not supported.
//!
//! @retval kStatus_Success;
status_t sim_device_mem_fill(uint32_t address, uint32_t length, uint32_t pattern);
#if defined(__cplusplus)
}
#endif // __cplusplus
#endif // _Memory_h_
////////////////////////////////////////////////////////////////////////////////
// EOF
////////////////////////////////////////////////////////////////////////////////

181
src/blfwk/SourceFile.h Normal file
View File

@ -0,0 +1,181 @@
/*
* Copyright (c) 2013-2014 Freescale Semiconductor, Inc.
* All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#if !defined(_SourceFile_h_)
#define _SourceFile_h_
#include <string>
#include <iostream>
#include <fstream>
#include "smart_ptr.h"
#include "DataSource.h"
#include "DataTarget.h"
#include "StringMatcher.h"
#include "OptionContext.h"
namespace blfwk
{
/*!
* \brief Abstract base class for a source file containing executable code.
*
* The purpose of this class cluster is to provide a common interface for
* accessing the contents of different file formats. This is accomplished
* through several small sets of methods along with the DataSource and
* DataTarget classes.
*
* The primary interface for creating instances of SourceFile is the static
* SourceFile::openFile() function. It will create the correct subclass of
* SourceFile by inspecting the file to determine its type.
*/
class SourceFile
{
public:
// \brief Factory function that creates the correct subclass of SourceFile.
static SourceFile *openFile(const std::string &path);
//! Set of supported executable image file formats.
enum source_file_t
{
kBinarySourceFile, //!< \see blfwk::BinarySourceFile
kELFSourceFile, //!< \see blfwk::ELFSourceFile
kIntelHexSourceFile, //!< \see blfwk::IntelHexSourceFile
kSBSourceFile, //!< \see blfwk::SBSourceFile
kSRecordSourceFile //!< \see blfwk::SRecordSourceFile
};
public:
//! \brief Default constructor.
SourceFile(const std::string &path, source_file_t filetype);
//! \brief Destructor.
virtual ~SourceFile();
//! \brief Set the option context.
//!
//! The source file will take ownership of the @a context and delete it
//! when the source file is itself deleted.
inline void setOptions(OptionContext *context) { m_options = context; }
//! \brief Return the option context.
inline const OptionContext *getOptions() const { return m_options; }
//! \brief Return the file type.
inline source_file_t getFileType() const { return m_filetype; }
//! \brief Returns the path to the file.
inline const std::string &getPath() const { return m_path; }
//! \brief Get the size in bytes of the file.
unsigned getSize() const { return m_size; }
//! \name Opening and closing
//@{
//! \brief Opens the file.
virtual void open();
//! \brief Closes the file.
virtual void close();
//! \brief Returns whether the file is already open.
virtual bool isOpen() const { return (bool)m_stream && const_cast<std::ifstream *>(m_stream.get())->is_open(); }
//@}
//! \name Format capabilities
//@{
virtual bool supportsNamedSections() const = 0;
virtual bool supportsNamedSymbols() const = 0;
//@}
//! \name Data source creation
//@{
//! \brief Creates a data source from the entire file.
virtual DataSource *createDataSource() = 0;
//! \brief Creates a data source out of one or more sections of the file.
//!
//! The \a selector object is used to perform the section name comparison.
//! If the file does not support named sections, or if there is not a
//! section with the given name, this method may return NULL.
virtual DataSource *createDataSource(StringMatcher &matcher) { return NULL; }
//! \brief Creates a data source out of one section of the file.
virtual DataSource *createDataSource(const std::string &section);
//@}
//! \name Entry point
//@{
//! \brief Returns true if an entry point was set in the file.
virtual bool hasEntryPoint() = 0;
//! \brief Returns the entry point address.
virtual uint32_t getEntryPointAddress() { return 0; }
//@}
//! \name Data target creation
//@{
virtual DataTarget *createDataTargetForSection(const std::string &section) { return NULL; }
virtual DataTarget *createDataTargetForSymbol(const std::string &symbol) { return NULL; }
virtual DataTarget *createDataTargetForEntryPoint();
//@}
//! \name Symbols
//@{
//! \brief Returns whether a symbol exists in the source file.
virtual bool hasSymbol(const std::string &name) { return false; }
//! \brief Returns the value of a symbol.
virtual uint32_t getSymbolValue(const std::string &name) { return 0; }
//! \brief Returns the size of a symbol.
virtual unsigned getSymbolSize(const std::string &name) { return 0; }
//@}
protected:
std::string m_path; //!< Path to the file.
smart_ptr<std::ifstream> m_stream; //!< File stream, or NULL if file is closed.
smart_ptr<OptionContext> m_options; //!< Table of option values.
source_file_t m_filetype; //!< Image file type.
unsigned m_size; //!< The size in bytes of the file.
//! \brief Internal access to the input stream object.
inline std::ifstream *getStream() { return m_stream; }
};
/*!
* \brief Binary data file.
*/
class BinarySourceFile : public SourceFile
{
public:
//! \brief Default constructor.
BinarySourceFile(const std::string &path, source_file_t sourceFileType = kBinarySourceFile);
//! \name Format capabilities
//@{
virtual bool supportsNamedSections() const { return false; }
virtual bool supportsNamedSymbols() const { return false; }
//@}
//! \name Data source creation
//@{
//! \brief Creates an unmapped data source from the entire file.
virtual DataSource *createDataSource();
//@}
//! \name Entry point
//@{
//! \brief Initialize entry point and stack pointer from assumed vetcor table
//! at the beginning of the file.
void guessEntryPointAndStackPointer();
//! \brief Returns true if an entry point was set in the file.
virtual bool hasEntryPoint() { return m_entry_point != 0xffffffff; }
//! \brief Returns the entry point address.
virtual uint32_t getEntryPointAddress() { return m_entry_point; }
//! \brief Returns the stack pointer.
uint32_t getStackPointer() { return m_stack_pointer; }
//@}
protected:
uint32_t m_entry_point;
uint32_t m_stack_pointer;
};
}; // namespace blfwk
#endif // _SourceFile_h_

109
src/blfwk/SpiPeripheral.h Normal file
View File

@ -0,0 +1,109 @@
/*
* Copyright 2020 - 2022 NXP
* All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*
*/
#ifndef _spi_peripheral_h_
#define _spi_peripheral_h_
#include "Peripheral.h"
#include "blfwk/spi.h"
#include "packet/command_packet.h"
//! @addtogroup spi_peripheral
//! @{
namespace blfwk
{
/*!
* @brief Peripheral that talks to the target device over SPI port hardware.
*/
class SpiPeripheral : public Peripheral
{
public:
//! @breif Constants.
enum _spi_peripheral_constants
{
// The read() implementation for the SpiPeripheral does not use this the timeout parameter.
kSpiPeripheral_UnusedTimeout = 0,
// Serial timeout is set to this default during init().
kSpiPeripheral_DefaultReadTimeoutMs = 1,
kSpiPeripheral_DefaultSpeedKHz = 100,
kSpiPeripheral_DefaultClockPolarity = 1,
kSpiPeripheral_DefaultClockPhase = 1,
kSpiPeripheral_DefaultBitSequence = 1,
kSpiPeripheral_DefaultBitsPerWord = 8,
};
public:
//! @brief Parameterized constructor that opens the serial port.
//!
//! Opens and configures the port. Throws exception if port configuration fails.
//!
//! @param port OS file path for SPI port. For example "/dev/spidev-0.0" on Linux.
//! @param speed Port speed in KHz, e.g. 100(means 100KHz).
//! @param polarity SPI clock polarity, 1 for active-high, 0 for active-low.
//! @param phase SPI clock phase, 1 for second clock edge, 0 for first clock edge.
//! @param sequence SPI data transfer bits sequence. 1 for LSB, 0 for MSB.
SpiPeripheral(const char *port,
long speed = kSpiPeripheral_DefaultSpeedKHz,
uint8_t polarity = kSpiPeripheral_DefaultClockPolarity,
uint8_t phase = kSpiPeripheral_DefaultClockPhase,
uint8_t sequence = kSpiPeripheral_DefaultBitSequence);
//! @brief Destructor.
virtual ~SpiPeripheral();
//! @brief Flush.
//!
//! should be called on an open SPI port in order to flush any remaining data in the SPI RX buffer
void flushRX();
//! @brief Read bytes.
//!
//! @param buffer Pointer to buffer.
//! @param requestedBytes Number of bytes to read.
//! @param actualBytes Number of bytes actually read.
//! @param timeoutMs Time in milliseconds to wait for read to complete.
virtual status_t read(uint8_t *buffer, uint32_t requestedBytes, uint32_t *actualBytes, uint32_t unused_timeoutMs);
//! @brief Write bytes.
//!
//! @param buffer Pointer to buffer to write
//! @param byteCount Number of bytes to write
virtual status_t write(const uint8_t *buffer, uint32_t byteCount);
//! @brief Return peripheral Type
virtual _host_peripheral_types get_type(void) { return kHostPeripheralType_SPI; }
protected:
//! @brief Initialize.
//!
//! Opens and configures the port.
//!
//! Note: following COM port configuration is assumed: 8 bits, 1 stop bit, no parity.
//!
//! @param port OS file path for SPI port. For example "/dev/spidev-0.0" on Linux.
//! @param speed Port speed in KHz, e.g. 100(means 100KHz).
//! @param polarity SPI clock polarity, 1 for active-high, 0 for active-low.
//! @param phase SPI clock phase, 1 for second clock edge, 0 for first clock edge.
//! @param direction SPI data transfer bits direction. 1 for LSB, 0 for MSB.
bool init(const char *port, long speed, uint8_t polarity, uint8_t phase, uint8_t direction);
int m_fileDescriptor; //!< Port file descriptor.
uint8_t m_buffer[kDefaultMaxPacketSize]; //!< Buffer for bytes used to build read packet.
uint32_t m_current_ReadTimeout; //!< The last value sent to serial_set_read_timeout().
};
} // namespace blfwk
//! @}
#endif // _spi_peripheral_h_
////////////////////////////////////////////////////////////////////////////////
// EOF
////////////////////////////////////////////////////////////////////////////////

198
src/blfwk/StELFFile.h Normal file
View File

@ -0,0 +1,198 @@
/*
* Copyright (c) 2013-2014 Freescale Semiconductor, Inc.
* All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#if !defined(_StELFFile_h_)
#define _StELFFile_h_
#include <iostream>
#include <map>
#include <stdexcept>
#include <string>
#include <vector>
#include "blfwk/ELF.h"
#include "blfwk/stdafx.h"
//! Variations of the ARM ELF format.
typedef enum
{
eIllegalVariant = 0, //!< Illegal variant.
eARMVariant = 1, //!< Standard ARM ELF specification.
eGHSVariant, //!< Green Hills Software variant.
eGCCVariant //!< GNU Compiler Collection variant.
} ELFVariant_t;
//! Possible ARM ELF symbol types.
typedef enum
{
eUnknownSymbol,
eARMSymbol,
eThumbSymbol,
eDataSymbol
} ARMSymbolType_t;
/*!
* \brief Parser for Executable and Linking Format (ELF) files.
*
* The stream passed into the constructor needs to stay open for the life
* of the object. This is because calls to getSectionDataAtIndex() and
* getSegmentDataAtIndex() read the data directly from the input stream.
*/
class StELFFile
{
public:
typedef std::vector<Elf32_Shdr>::const_iterator const_section_iterator;
typedef std::vector<Elf32_Phdr>::const_iterator const_segment_iterator;
public:
//! \brief Constructor.
StELFFile(std::istream &inStream);
//! \brief Destructor.
virtual ~StELFFile();
//! \name File format variant
//@{
//! \brief Return the ELF format variant to which this file is set.
virtual ELFVariant_t ELFVariant() { return m_elfVariant; }
//! \brief Set the ELF format variation to either #eARMVariant or #eGHSVariant.
virtual void setELFVariant(ELFVariant_t variant) { m_elfVariant = variant; }
//@}
//! \name File name
//@{
virtual void setName(const std::string &inName) { m_name = inName; }
virtual std::string getName() const { return m_name; }
//@}
//! \name ELF header
//@{
//! \brief Returns the ELF file header.
inline const Elf32_Ehdr &getFileHeader() const { return m_header; }
//@}
//! \name Sections
//! Methods pertaining to the object file's sections.
//@{
//! \brief Returns the number of sections in the file.
inline unsigned getSectionCount() const { return static_cast<unsigned>(m_sectionHeaders.size()); }
//! \brief Returns a reference to section number \a inIndex.
const Elf32_Shdr &getSectionAtIndex(unsigned inIndex) const;
inline const_section_iterator getSectionBegin() const { return m_sectionHeaders.begin(); }
inline const_section_iterator getSectionEnd() const { return m_sectionHeaders.end(); }
//! \brief Returns the index of the section with the name \a inName.
unsigned getIndexOfSectionWithName(const std::string &inName);
//! \brief Returns the data for the section.
uint8_t *getSectionDataAtIndex(unsigned inIndex);
//! \brief Returns the data for the section.
uint8_t *getSectionData(const_section_iterator inSection);
//@}
//! \name Segments
//! Methods for accessing the file's program headers for segments.
//@{
//! \brief Returns the number of segments, or program headers, in the file.
inline unsigned getSegmentCount() const { return static_cast<unsigned>(m_programHeaders.size()); }
//! \brief Returns a reference to the given segment.
const Elf32_Phdr &getSegmentAtIndex(unsigned inIndex) const;
inline const_segment_iterator getSegmentBegin() const { return m_programHeaders.begin(); }
inline const_segment_iterator getSegmentEnd() const { return m_programHeaders.end(); }
//! \brief Returns the data of the specified segment.
uint8_t *getSegmentDataAtIndex(unsigned inIndex);
//! \brief Returns the data of the specified segment.
uint8_t *getSegmentData(const_segment_iterator inSegment);
//@}
//! \name String table
//! Methods for accessing the string tables.
//@{
//! \brief Returns a string from the file's section name string table.
std::string getSectionNameAtIndex(unsigned inIndex);
//! \brief Returns a string from any string table in the object file.
std::string getStringAtIndex(unsigned inStringTableSectionIndex, unsigned inStringIndex);
//@}
//! \name Symbol table
//! Methods for accessing the object file's symbol table. Currently only
//! a single symbol table with the section name ".symtab" is supported.
//@{
//! \brief Returns the number of symbols in the default ".symtab" symbol table.
unsigned getSymbolCount();
//! \brief Returns the symbol with index \a inIndex.
const Elf32_Sym &getSymbolAtIndex(unsigned inIndex);
//! \brief Returns the section index of the string table containing symbol names.
unsigned getSymbolNameStringTableIndex() const;
//! \brief Returns the name of the symbol described by \a inSymbol.
std::string getSymbolName(const Elf32_Sym &inSymbol);
unsigned getIndexOfSymbolAtAddress(uint32_t symbolAddress, bool strict = true);
ARMSymbolType_t getTypeOfSymbolAtIndex(unsigned symbolIndex);
//@}
//! \name Debugging
//@{
void dumpSections();
void dumpSymbolTable();
//@}
protected:
std::istream &m_stream; //!< The source stream for the ELF file.
ELFVariant_t m_elfVariant; //!< Variant of the ARM ELF format specification.
std::string m_name; //!< File name. (optional)
Elf32_Ehdr m_header; //!< The ELF file header.
std::vector<Elf32_Shdr> m_sectionHeaders; //!< All of the section headers.
std::vector<Elf32_Phdr> m_programHeaders; //!< All of the program headers.
unsigned m_symbolTableIndex; //!< Index of ".symtab" section, or #SHN_UNDEF if not present.
/*!
* Little structure containing information about cached section data.
*/
struct SectionDataInfo
{
uint8_t *m_data; //!< Pointer to section data.
unsigned m_size; //!< Section data size in bytes.
bool m_swapped; //!< Has this section been byte swapped yet? Used for symbol table.
};
typedef std::map<unsigned, SectionDataInfo> SectionDataMap;
SectionDataMap m_sectionDataCache; //!< Cached data of sections.
//! \brief Reads a section's data either from cache or from disk.
SectionDataInfo &getCachedSectionData(unsigned inSectionIndex);
//! \brief Reads the file, section, and program headers into memory.
void readFileHeaders();
uint8_t *readSectionData(const Elf32_Shdr &inHeader);
uint8_t *readSegmentData(const Elf32_Phdr &inHeader);
//! \brief Byte swaps the symbol table data into host endianness.
void byteSwapSymbolTable(const Elf32_Shdr &header, SectionDataInfo &info);
};
/*!
* \brief Simple exception thrown to indicate an error in the input ELF file format.
*/
class StELFFileException : public std::runtime_error
{
public:
//! \brief Default constructor.
StELFFileException(const std::string &inMessage)
: std::runtime_error(inMessage)
{
}
};
#endif // _StELFFile_h_

View File

@ -0,0 +1,257 @@
/*
* Copyright (c) 2013-2014 Freescale Semiconductor, Inc.
* All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#if !defined(_StExecutableImage_h_)
#define _StExecutableImage_h_
#include "blfwk/stdafx.h"
#include <list>
/*!
* \brief Used to build a representation of memory regions.
*
* An intermediate representation of the memory regions and segments loaded
* from an executable file. Also used to find contiguous segments that are
* specified separately in the source file.
*
* When regions are added, an attempt is made to coalesce contiguous regions.
* In order for this to succeed, the touching regions must be of the same
* type and have the same permissions. Regions are also kept sorted by their
* address range as they are added.
*
* \todo Implement alignment support.
*/
class StExecutableImage
{
public:
//! Possible types of memory regions.
typedef enum
{
TEXT_REGION, //!< A region containing data or instructions.
FILL_REGION //!< Region to be initialized with zero bytes.
} MemoryRegionType;
//! Memory region flag constants.
enum
{
REGION_READ_FLAG = 1, //!< Region is readable.
REGION_WRITE_FLAG = 2, //!< Region is writable.
REGION_EXEC_FLAG = 4, //!< Region may contain executable code.
REGION_RW_FLAG = REGION_READ_FLAG | REGION_WRITE_FLAG, //!< Region is read-write.
//! Mask to access only permissions flags for a region.
REGION_PERM_FLAG_MASK = 0x7
};
/*!
* Representation of a contiguous region of memory.
*
* \todo Add comparison operators so we can use the STL sort algorithm.
*/
struct MemoryRegion
{
MemoryRegionType m_type; //!< Memory region type.
uint32_t m_address; //!< The 32-bit start address of this region.
uint32_t m_length; //!< Number of bytes in this region.
uint8_t *m_data; //!< Pointer to data. Will be NULL for FILL_REGION type.
unsigned m_flags; //!< Flags for the region.
//! \brief Calculates the address of the last byte occupied by this region.
inline uint32_t endAddress() const { return m_address + m_length - 1; }
//! \brief Equality operator.
bool operator==(const MemoryRegion &other) const;
};
//! A list of #StExecutableImage::MemoryRegion objects.
typedef std::list<MemoryRegion> MemoryRegionList;
//! The iterator type used to access #StExecutableImage::MemoryRegion objects. This type
//! is used by the methods #getRegionBegin() and #getRegionEnd().
typedef MemoryRegionList::const_iterator const_iterator;
//! The possible actions for regions matching an address filter range.
typedef enum
{
ADDR_FILTER_NONE, //!< Do nothing.
ADDR_FILTER_ERROR, //!< Raise an error exception.
ADDR_FILTER_WARNING, //!< Raise a warning exception.
ADDR_FILTER_CROP //!< Don't include the matching address range in the executable image.
} AddressFilterAction;
/*!
* An address filter consists of a single address range and an action. If a
* memory region overlaps the filter's range then the action will be performed.
* The possible filter actions are defined by the #AddressFilterAction enumeration.
*/
struct AddressFilter
{
AddressFilterAction m_action; //!< Action to be performed when the filter is matched.
uint32_t m_fromAddress; //!< Start address of the filter. Should be lower than or equal to #m_toAddress.
uint32_t m_toAddress; //!< End address of the filter. Should be higher than or equal to #m_fromAddress.
unsigned m_priority; //!< Priority for this filter. Zero is the lowest priority.
//! \brief Constructor.
AddressFilter(AddressFilterAction action, uint32_t from, uint32_t to, unsigned priority = 0)
: m_action(action)
, m_fromAddress(from)
, m_toAddress(to)
, m_priority(priority)
{
}
//! \brief Test routine.
bool matchesMemoryRegion(const MemoryRegion &region) const;
//! \brief Compares two address filter objects.
int compare(const AddressFilter &other) const;
//! \name Comparison operators
//@{
inline bool operator<(const AddressFilter &other) const { return compare(other) == -1; }
inline bool operator>(const AddressFilter &other) const { return compare(other) == 1; }
inline bool operator==(const AddressFilter &other) const { return compare(other) == 0; }
inline bool operator<=(const AddressFilter &other) const { return compare(other) != 1; }
inline bool operator>=(const AddressFilter &other) const { return compare(other) != -1; }
//@}
};
//! List of #StExecutableImage::AddressFilter objects.
typedef std::list<AddressFilter> AddressFilterList;
//! The exception class raised for the #ADDR_FILTER_ERROR and #ADDR_FILTER_WARNING
//! filter actions.
class address_filter_exception
{
public:
//! \brief Constructor.
//!
//! A local copy of \a matchingFilter is made, in case the image and/or filter
//! are on the stack and would be disposed of when the exception is raised.
address_filter_exception(bool isError, std::string &imageName, const AddressFilter &matchingFilter)
: m_isError(isError)
, m_imageName(imageName)
, m_filter(matchingFilter)
{
}
//! \brief Returns true if the exception is an error. Otherwise the exception
//! is for a warning.
inline bool isError() const { return m_isError; }
//! \brief
inline std::string getImageName() const { return m_imageName; }
//! \brief
inline const AddressFilter &getMatchingFilter() const { return m_filter; }
protected:
bool m_isError;
std::string m_imageName;
AddressFilter m_filter;
};
public:
//! \brief Constructor.
StExecutableImage(int inAlignment = 256);
//! \brief Copy constructor.
StExecutableImage(const StExecutableImage &inOther);
//! \brief Destructor.
virtual ~StExecutableImage();
//! \name Image name
//! Methods for getting and setting the image name.
//@{
//! \brief Sets the image's name to \a inName.
virtual void setName(const std::string &inName);
//! \brief Returns a copy of the image's name.
virtual std::string getName() const;
//@}
//! \name Regions
//! Methods to add and access memory regions.
//@{
//! \brief Add a region to be filled with zeroes.
virtual void addFillRegion(uint32_t inAddress, unsigned inLength);
//! \brief Add a region containing data to be loaded.
virtual void addTextRegion(uint32_t inAddress, const uint8_t *inData, unsigned inLength);
//! \brief Returns the total number of regions.
//!
//! Note that this count may not be the same as the number of calls to
//! addFillRegion() and addTextRegion() due to region coalescing.
inline unsigned getRegionCount() const { return static_cast<unsigned>(m_image.size()); }
//! \brief Returns a reference to the region specified by \a inIndex.
const MemoryRegion &getRegionAtIndex(unsigned inIndex) const;
//! \brief Return an iterator to the first region.
inline const_iterator getRegionBegin() const { return m_image.begin(); }
//! \brief Return an iterator to the next-after-last region.
inline const_iterator getRegionEnd() const { return m_image.end(); }
//@}
//! \name Entry point
//@{
//! \brief Sets the entry point address.
inline void setEntryPoint(uint32_t inEntryAddress)
{
m_entry = inEntryAddress;
m_hasEntry = true;
}
//! \brief Returns true if an entry point has been set.
inline bool hasEntryPoint() const { return m_hasEntry; }
//! \brief Returns the entry point address.
inline uint32_t getEntryPoint() const { return hasEntryPoint() ? m_entry : 0; }
//@}
//! \name Address filter
//@{
//! \brief Add a new address filter.
virtual void addAddressFilter(const AddressFilter &filter);
//! \brief Add multiple address filters at once.
//!
//! The template argument \a _T must be an iterator or const iterator that
//! dereferences to an StExecutableImage::AddressFilter reference. All filters
//! from \a from to \a to will be added to the address filter list.
template <typename _T>
void addAddressFilters(_T from, _T to)
{
_T it = from;
for (; it != to; ++it)
{
addAddressFilter(*it);
}
}
//! \brief Remove all active filters.
virtual void clearAddressFilters();
//! \brief Process all active filters and perform associated actions.
virtual void applyAddressFilters();
//@}
protected:
std::string m_name; //!< The name of the image (can be a file name, for instance).
int m_alignment; //!< The required address alignment for each memory region.
bool m_hasEntry; //!< True if an entry point has been set.
uint32_t m_entry; //!< Entry point address.
MemoryRegionList m_image; //!< The memory regions.
AddressFilterList m_filters; //!< List of active address filters.
//! \brief Deletes the portion \a region that overlaps \a filter.
void cropRegionToFilter(MemoryRegion &region, const AddressFilter &filter);
//! \brief Inserts the region in sorted order or merges with one already in the image.
void insertOrMergeRegion(MemoryRegion &inRegion);
//! \brief Merges two memory regions into one.
void mergeRegions(MemoryRegion &inOldRegion, MemoryRegion &inNewRegion);
};
#endif // _StExecutableImage_h_

155
src/blfwk/StIntelHexFile.h Normal file
View File

@ -0,0 +1,155 @@
/*
* Copyright (c) 2013-2015 Freescale Semiconductor, Inc.
* All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#if !defined(_StIntelHexFile_h_)
#define _StIntelHexFile_h_
#include "stdafx.h"
#include <istream>
#include <string>
#include <vector>
#include <stdexcept>
enum
{
//! The required first character of a Intel Hex
INTELHEX_START_CHAR = ':',
//! The minimum length of a Hex. This is the start char (1) + datacount (2) +
//! addr (4) + type (2) + check sum (2).
INTELHEX_MIN_LENGTH = 11,
//! Index of the first character of the address field.
INTELHEX_ADDRESS_START_CHAR_INDEX = 3,
//! Index of the first character of the record type field.
INTELHEX_TYPE_START_CHAR_INDEX = 7,
//! Index of the first character of the record type field.
INTELHEX_DATA_START_CHAR_INDEX = 9
};
//! Intel Hex Record Type
enum
{
//! Data Record, which contains data and a 16-bit start address for the data.
INTELHEX_RECORD_DATA = 0x00,
//! End of File Record, which specifies the end of the hex file, and
//! must occur exactly once per file in the last line of the file.
INTELHEX_RECORD_END_OF_FILE = 0x01,
//! Extended Segment Address Record, which is used to specify bits 4- 19 of the Segment Base Address.
INTELHEX_RECORD_EXTENDED_SEGMENT_ADDRESS = 0x02,
//! Start Segment Address Record, which is used to specify the execution start address for the object file.
INTELHEX_RECORD_START_SEGMENT_ADDRESS = 0x03,
//! Extended Linear Address Record, which is used to specify bits 16- 31 of the Linear Base Address.
INTELHEX_RECORD_EXTENDED_LINEAR_ADDRESS = 0x04,
//! Start Linear Address Record, which is used to specify the execution start address for the object file.
INTELHEX_RECORD_START_LINEAR_ADDRESS = 0x05
};
/*!
* \brief Intel Hex parser.
*
* This class takes an input stream and parses it as a Intel Hex file. While
* the individual records that comprise the file are available for access, the
* class also provides a higher-level view of the contents. It processes the
* individual records and builds an image of what the memory touched by the
* file looks like. Then you can access the contiguous sections of memory.
*/
class StIntelHexFile
{
public:
/*!
* Structure representing each individual line of the Intel Hex input data.
*/
struct IntelHex
{
unsigned m_dataCount; //!< The number of bytes in the data field.
uint32_t m_address; //!< The address offset of the data.
unsigned m_type; //!< Type of the data field. 00: Data
//!< 01: End of File
//!< 02: Extended Segment Address
//!< 03: Start Segment Address
//!< 04: Extended Linear Address
//!< 05: Start Linear Address
uint8_t *m_data; //!< Pointer to data, or NULL if no data for this record.
uint8_t m_checksum; //!< The checksum byte used to verify the record.
};
//! Iterator type.
typedef std::vector<IntelHex>::const_iterator const_iterator;
public:
//! \brief Constructor.
StIntelHexFile(std::istream &inStream);
//! \brief Destructor.
virtual ~StIntelHexFile();
//! \name File name
//@{
virtual void setName(const std::string &inName) { m_name = inName; }
virtual std::string getName() const { return m_name; }
//@}
//! \name Parsing
//@{
//! \brief Determine if the file is a Intel Hex file.
virtual bool isIntelHexFile();
//! \brief Parse the entire IntelHex input stream.
virtual void parse();
//@}
//! \name Record access
//@{
//! \return the number of Intel Hex that have been parsed from the input stream.
inline unsigned getRecordCount() const { return static_cast<unsigned>(m_records.size()); }
//! \return iterator for
inline const_iterator getBegin() const { return m_records.begin(); }
inline const_iterator getEnd() const { return m_records.end(); }
//@}
//! \name Operators
//@{
inline const IntelHex &operator[](unsigned inIndex) { return m_records[inIndex]; }
//@}
protected:
std::istream &m_stream; //!< The input stream for the Intel Hex data.
std::vector<IntelHex> m_records; //!< Vector of Intel Hex in the input data.
std::string m_name; //!< File name. (optional)
//! \name Parsing utilities
//@{
virtual void parseLine(std::string &inLine);
bool isHexDigit(char c);
int hexDigitToInt(char digit);
int readHexByte(std::string &inString, int inIndex);
//@}
};
/*!
* \brief Simple exception thrown to indicate an error in the input Intel Hex data format.
*/
class StIntelHexParseException : public std::runtime_error
{
public:
//! \brief Default constructor.
StIntelHexParseException(const std::string &inMessage)
: std::runtime_error(inMessage)
{
}
};
#endif // _StIntelHexFile_h_

122
src/blfwk/StSRecordFile.h Normal file
View File

@ -0,0 +1,122 @@
/*
* Copyright (c) 2013-2014 Freescale Semiconductor, Inc.
* All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#if !defined(_StSRecordFile_h_)
#define _StSRecordFile_h_
//#include <stdint.h>
#include "stdafx.h"
#include <istream>
#include <string>
#include <vector>
#include <stdexcept>
enum
{
//! The required first character of an S-record.
SRECORD_START_CHAR = 'S',
//! The minimum length of a S-record. This is the type (2) + count (2) + addr (4) + cksum (2).
SRECORD_MIN_LENGTH = 10,
//! Index of the first character of the address field.
SRECORD_ADDRESS_START_CHAR_INDEX = 4
};
/*!
* \brief S-record parser.
*
* This class takes an input stream and parses it as an S-record file. While
* the individual records that comprise the file are available for access, the
* class also provides a higher-level view of the contents. It processes the
* individual records and builds an image of what the memory touched by the
* file looks like. Then you can access the contiguous sections of memory.
*/
class StSRecordFile
{
public:
/*!
* Structure representing each individual line of the S-record input data.
*/
struct SRecord
{
unsigned m_type; //!< Record number type, such as 9 for "S9", 3 for "S3" and so on.
unsigned m_count; //!< Number of character pairs (bytes) from address through checksum.
uint32_t m_address; //!< The address specified as part of the S-record.
unsigned m_dataCount; //!< Number of bytes of data.
uint8_t *m_data; //!< Pointer to data, or NULL if no data for this record type.
uint8_t m_checksum; //!< The checksum byte present in the S-record.
};
//! Iterator type.
typedef std::vector<SRecord>::const_iterator const_iterator;
public:
//! \brief Constructor.
StSRecordFile(std::istream &inStream);
//! \brief Destructor.
virtual ~StSRecordFile();
//! \name File name
//@{
virtual void setName(const std::string &inName) { m_name = inName; }
virtual std::string getName() const { return m_name; }
//@}
//! \name Parsing
//@{
//! \brief Determine if the file is an S-record file.
virtual bool isSRecordFile();
//! \brief Parses the entire S-record input stream.
virtual void parse();
//@}
//! \name Record access
//@{
//! \return the number of S-records that have been parsed from the input stream.
inline unsigned getRecordCount() const { return static_cast<unsigned>(m_records.size()); }
//! \return iterator for
inline const_iterator getBegin() const { return m_records.begin(); }
inline const_iterator getEnd() const { return m_records.end(); }
//@}
//! \name Operators
//@{
inline const SRecord &operator[](unsigned inIndex) { return m_records[inIndex]; }
//@}
protected:
std::istream &m_stream; //!< The input stream for the S-record data.
std::vector<SRecord> m_records; //!< Vector of S-records in the input data.
std::string m_name; //!< File name. (optional)
//! \name Parsing utilities
//@{
virtual void parseLine(std::string &inLine);
bool isHexDigit(char c);
int hexDigitToInt(char digit);
int readHexByte(std::string &inString, int inIndex);
//@}
};
/*!
* \brief Simple exception thrown to indicate an error in the input SRecord data format.
*/
class StSRecordParseException : public std::runtime_error
{
public:
//! \brief Default constructor.
StSRecordParseException(const std::string &inMessage)
: std::runtime_error(inMessage)
{
}
};
#endif // _StSRecordFile_h_

60
src/blfwk/StringMatcher.h Normal file
View File

@ -0,0 +1,60 @@
/*
* Copyright (c) 2013-2014 Freescale Semiconductor, Inc.
* All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#if !defined(_StringMatcher_h_)
#define _StringMatcher_h_
#include <string>
namespace blfwk
{
/*!
* \brief Abstract interface class used to select strings by name.
*/
class StringMatcher
{
public:
//! \brief Performs a single string match test against testValue.
//!
//! \retval true The \a testValue argument matches.
//! \retval false No match was made against the argument.
virtual bool match(const std::string &testValue) = 0;
};
/*!
* \brief String matcher subclass that matches all test strings.
*/
class WildcardMatcher : public StringMatcher
{
public:
//! \brief Always returns true, indicating a positive match.
virtual bool match(const std::string &testValue) { return true; }
};
/*!
* \brief Simple string matcher that compares against a fixed value.
*/
class FixedMatcher : public StringMatcher
{
public:
//! \brief Constructor. Sets the string to compare against to be \a fixedValue.
FixedMatcher(const std::string &fixedValue)
: m_value(fixedValue)
{
}
//! \brief Returns whether \a testValue is the same as the value passed to the constructor.
//!
//! \retval true The \a testValue argument matches the fixed compare value.
//! \retval false The argument is not the same as the compare value.
virtual bool match(const std::string &testValue) { return testValue == m_value; }
protected:
const std::string &m_value; //!< The section name to look for.
};
}; // namespace blfwk
#endif // _StringMatcher_h_

View File

@ -0,0 +1,95 @@
/*
* Copyright (c) 2013-2014 Freescale Semiconductor, Inc.
* Copyright 2015-2020 NXP
* All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef _uart_peripheral_h_
#define _uart_peripheral_h_
#include "Peripheral.h"
#include "packet/command_packet.h"
//! @addtogroup uart_peripheral
//! @{
namespace blfwk
{
/*!
* @brief Peripheral that talks to the target device over COM port hardware.
*/
class UartPeripheral : public Peripheral
{
public:
//! @breif Constants.
enum _uart_peripheral_constants
{
// The read() implementation for the UartPeripheral does not use this the timeout parameter.
kUartPeripheral_UnusedTimeout = 0,
// Serial timeout is set to this default during init().
kUartPeripheral_DefaultReadTimeoutMs = 1000,
kUartPeripheral_DefaultBaudRate = 9600
};
public:
//! @brief Parameterized constructor that opens the serial port.
//!
//! Opens and configures the port. Throws exception if port configuration fails.
//!
//! Note: following COM port configuration is assumed: 8 bits, 1 stop bit, no parity.
//!
//! @param port OS file path for COM port. For example "COM1" on Windows.
//! @param speed Port speed, e.g. 9600.
UartPeripheral(const char *port, long speed = kUartPeripheral_DefaultBaudRate);
//! @brief Destructor.
virtual ~UartPeripheral();
//! @brief Flush.
//!
//! should be called on an open COM port in order to flush any remaining data in the UART RX buffer
void flushRX();
//! @brief Read bytes.
//!
//! @param buffer Pointer to buffer.
//! @param requestedBytes Number of bytes to read.
//! @param actualBytes Number of bytes actually read.
//! @param timeoutMs Time in milliseconds to wait for read to complete.
virtual status_t read(uint8_t *buffer, uint32_t requestedBytes, uint32_t *actualBytes, uint32_t unused_timeoutMs);
//! @brief Write bytes.
//!
//! @param buffer Pointer to buffer to write
//! @param byteCount Number of bytes to write
virtual status_t write(const uint8_t *buffer, uint32_t byteCount);
//! @brief Return peripheral Type
virtual _host_peripheral_types get_type(void) { return kHostPeripheralType_UART; }
protected:
//! @brief Initialize.
//!
//! Opens and configures the port.
//!
//! Note: following COM port configuration is assumed: 8 bits, 1 stop bit, no parity.
//!
//! @param port OS file path for COM port. For example "COM1" on Windows.
//! @param speed Port speed, e.g. 9600.
bool init(const char *port, long speed);
char *port_name; //!< Port name
int m_fileDescriptor; //!< Port file descriptor.
uint8_t m_buffer[kDefaultMaxPacketSize]; //!< Buffer for bytes used to build read packet.
};
} // namespace blfwk
//! @}
#endif // _uart_peripheral_h_
////////////////////////////////////////////////////////////////////////////////
// EOF
////////////////////////////////////////////////////////////////////////////////

324
src/blfwk/Updater.h Normal file
View File

@ -0,0 +1,324 @@
/*
* Copyright (c) 2013-2014 Freescale Semiconductor, Inc.
* Copyright 2015-2020 NXP.
* All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#if !defined(_Updater_h_)
#define _Updater_h_
#include "Bootloader.h"
#include "SourceFile.h"
//! @addtogroup host_updater
//! @{
using namespace blfwk;
namespace blfwk
{
//! @name Updater states with descriptions.
//@{
struct updater_enum_t
{
uint32_t value;
std::string description;
updater_enum_t()
: value(0)
, description("")
{
}
updater_enum_t(uint32_t value, const char *description)
: value(value)
, description(description)
{
}
updater_enum_t(const updater_enum_t &old_enum)
{
value = old_enum.value;
description = old_enum.description.c_str();
}
};
const updater_enum_t kUpdaterState_NotReady(0, "Not ready");
const updater_enum_t kUpdaterState_Ready(1, "Ready");
const updater_enum_t kUpdaterState_Working(2, "Working");
const updater_enum_t kUpdaterState_Idle(3, "Idle");
const updater_enum_t kUpdaterState_Complete(4, "Complete");
//@}
//! @name Updater tasks with descriptions.
//@{
const updater_enum_t kUpdaterTask_Erasing(0, "Erasing");
const updater_enum_t kUpdaterTask_Flashing(1, "Writing");
const updater_enum_t kUpdaterTask_Reseting(2, "Reseting");
const updater_enum_t kUpdaterTask_Executing(3, "Jumping");
struct updater_task_t
{
updater_enum_t task_desc;
uint32_t current;
uint32_t total;
updater_task_t(const updater_enum_t &task_desc, uint32_t total)
: task_desc(task_desc)
, current(0)
, total(total)
{
}
updater_task_t()
: task_desc()
, current(0)
, total(0)
{
}
};
typedef std::vector<updater_task_t> updater_task_vector_t;
//! @name Updater operations with descriptions.
//@{
const updater_enum_t kUpdaterOperation_Update(0, "Update");
//! @name Updater operation.
//@{
struct updater_operation_t
{
updater_enum_t operation_desc;
updater_task_vector_t tasks;
uint32_t current_task;
bool user_stopped;
uint32_t current()
{
uint32_t current = 0;
for (uint32_t i = 0; i < current_task; ++i)
{
current += tasks[i].total;
}
current += tasks[current_task].current;
return current;
}
uint32_t total()
{
uint32_t total = 0;
for (uint32_t i = 0; i < tasks.size(); ++i)
{
total += tasks[i].total;
}
return total;
}
updater_operation_t(updater_enum_t operation_desc)
: operation_desc(operation_desc)
, tasks()
, current_task(0)
, user_stopped(false)
{
}
updater_operation_t(uint32_t value, const char *description)
: operation_desc(value, description)
, tasks()
, current_task(0)
, user_stopped(false)
{
}
};
//@}
/*!
* \brief Update class contains the functionality necessary to update the
* firmware on a device running Bootloader.
*
* The purpose of this class is to provide a common interface for
* updating any device running the Bootloader from several different file formats.
*/
class Updater : public Bootloader
{
public:
//! \brief Default constructor.
Updater(const Peripheral::PeripheralConfigData &config);
//! \brief Destructor.
virtual ~Updater();
//! \name Update API.
//@{
//! @brief Type for the progress callback routine.
typedef void (*progress_callback_t)(updater_operation_t *op);
//! @brief Struct used to monitor the Operation progress.
updater_operation_t m_operation;
//! \brief Set the user-defined function to call on progress events.
//!
//! \param callback The function to callback with the progress data.
void setCallback(progress_callback_t callback) { m_progressCallback = callback; }
//! \brief Set callback for progress and abort control.
//!
//! \param callback The function to callback with the progress data.
//! \param abort The variable used for abort phase control.
void registerCallback(void (*callback)(int, int, int), bool *abort)
{
m_progress.registerCallback(callback, abort);
}
//! \brief Program flash on the device.
//!
//! \exception std::runtime_error Raised if the file could not be opened successfully.
//!
//! \param filename The file to program into the device.
//! \param base_address The address on the device where the file wiill be written.
status_t flashFirmware(const char *filename, uint32_t base_address, uint32_t memoryId);
//! \brief Erase all flash blocks and release MCU security
//!
//! \exception std::runtime_error Raised if the FlashEraseAllUnsecure command does not
//! return success.
//! Raised if the FlashEraseAllUnsecure command is not
//! supported.
void eraseAllUnsecure();
//! \brief Erase the specified FLASH region.
//!
//! \exception std::runtime_error Thrown if an error occurred.
//!
//! \param start The beginning address of the memory region to be erased.
//!
//! \param length The length in bytes of the memory region to be erased.
//!
//! \param memoryId The ID of the memory to erase.
void eraseRegion(uint32_t start, uint32_t length, uint32_t memoryId);
//! \brief Execute the FlashEraseAll bootloader command.
//!
//! \exception std::runtime_error Thrown if an error occurred
//!
//! \param memoryId The ID of the memory to erase.
void eraseAll(uint32_t memoryId);
//! \brief Release security using BackdoorKey
//!
//! \exception std::runtime_error Raised if the FlashSecurityDisable command does not
//! return success.
//! Raised if the FlashSecurityDisable command is not
//! supported.
//! Raised if the parameter is illegal
//! \param backdoor_key The 16 hex digitals used to release the security
void unlock(string backdoor_key);
//! \brief get total internal flash size of current device.
//!
//! \exception std::runtime_error Raised if the operation is failed.
//!
//! \return the size in bytes. Return 0 means no internal Flash available.
uint32_t getInternalFlashSize(void);
//! \brief get total internal RAM size of current device.
//!
//! \exception std::runtime_error Raised if the operation is failed.
//!
//! \return the size in bytes. Return 0 means no internal RAM available.
uint32_t getInternalRAMSize(void);
//! \brief Execute the FlashProgramOnce bootloader command.
//!
//! \exception std::runtime_error Thrown if an error occurred while sending the
//! FlashEraseAll bootloader command.
//!
//! \param index The index of a specific program once field.
//!
//! \param byteCount The length in bytes of a specific program once field.
//!
//! \param data The 8/16 hex digitals to write.
void programOnce(uint32_t index, uint32_t byteCount, string data, bool isLsb);
//@}
//
protected:
//! \name Bootloader commands
//@{
//! \brief Execute the FlashEraseRegion bootloader command.
//!
//! \exception std::runtime_error Thrown if an error occurred while sending the
//! FlashEraseRegion(start, length) bootloader command.
//!
//! \param start The beginning address of the memory region to be erased.
//!
//! \param length The length in bytes of the memory region to be erased.
void eraseFlashRegion(uint32_t start, uint32_t length);
//! \brief Execute the FlashEraseAll bootloader command.
//!
//! \exception std::runtime_error Thrown if an error occurred while sending the
//! FlashEraseAll bootloader command.
void eraseFlashAll();
//! \brief Execute the write-memory bootloader command.
//!
//! \exception std::runtime_error Thrown if an error occurred while sending the
//! WriteMemory(segment) bootloader command.
//!
//! \param [in,out] segment The DatSource::Segment that represents the data to be written to the device.
void writeMemory(DataSource::Segment *segment);
//! \brief Execute the write-memory bootloader command.
//!
//! \exception std::runtime_error Thrown if an error occurred while sending the
//! WriteMemory(vector<uint8_t) bootloader command.
//!
//! \param [in] data A vector<uchar> refernce that contains the data to be written to the device.
//! \param [in] address The address on the device where the data will be written.
void writeMemory(uint32_t address, const uchar_vector_t &data);
//! \brief Execute the write-memory bootloader command.
//!
//! \exception std::runtime_error Thrown if an error occurred while sending the
//! WriteMemory(segment) bootloader command.
//!
//! \param [in,out] segment The DatSource::Segment that represents the data to be written to the device.
void fuseProgram(DataSource::Segment *segment);
//! \brief Execute the write-memory bootloader command.
//!
//! \exception std::runtime_error Thrown if an error occurred while sending the
//! WriteMemory(vector<uint8_t) bootloader command.
//!
//! \param [in] data A vector<uchar> refernce that contains the data to be written to the device.
//! \param [in] address The address on the device where the data will be written.
void fuseProgram(uint32_t address, const uchar_vector_t &data);
//! \brief Program flash procedure for SourceFile types.
status_t flashFromSourceFile();
//! \brief Program flash procedure for SB files.
status_t flashFromSBFile(const char *filename);
//! \brief Check if the memory is supported by current device.
bool isMemorySupported(uint32_t memoryId);
protected:
uint32_t m_base_address; //!< Base address of the image.
SourceFile *m_sourceFile; //!< SourceFile object.
uint32_t m_memoryId; //!< ID of the memory to flush the image to.
progress_callback_t m_progressCallback; //!< Callback used to report update progress.
Progress m_progress; //!< Progress control.
standard_version_t m_version; //!< Version of the bootloader running on current device.
};
}; // namespace blfwk
//! @}
#endif // _Updater_h_

View File

@ -0,0 +1,104 @@
/*
* Copyright (c) 2013-2014 Freescale Semiconductor, Inc.
* Copyright 2015-2020 NXP.
* All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef _usb_hid_packetizer_h_
#define _usb_hid_packetizer_h_
#include "Packetizer.h"
#include "UsbHidPeripheral.h"
#include "hidapi.h"
#include "bootloader_common.h"
#include "bootloader_hid_report_ids.h"
//! @addtogroup usb_hid_packetizer
//! @{
namespace blfwk
{
/*!
* @brief Provides source and sink for packets that go over USB HID class.
*/
class UsbHidPacketizer : public Packetizer
{
public:
//! @brief Constants
enum _usbhid_contants
{
kReadFlushTimeoutMs = 100000,
kPollAbortTimeoutMs = 10,
kPollPacketMaxRetryCnt = 50,
kContinuousReadMargin = 2,
};
public:
//! @brief Default Constructor.
UsbHidPacketizer(UsbHidPeripheral *peripheral, uint32_t readPacketTimeoutMs);
//! @brief Destructor.
virtual ~UsbHidPacketizer();
//! @brief Read a packet.
//!
//! Provides the address of a buffer containing the packet.
//!
//! @param packet Pointer location to write packet pointer
//! @param packetLength Number of bytes in returned packet
virtual status_t readPacket(uint8_t **packet, uint32_t *packetLength, packet_type_t packetType);
//! @brief Write a packet.
//!
//! @param packet Pointer to packet to write
//! @param byteCount Number of bytes in packet
virtual status_t writePacket(const uint8_t *packet, uint32_t byteCount, packet_type_t packetType);
//! @brief Abort data phase.
virtual void abortPacket();
//! @brief Send framing packet ack/nak.
virtual void sync(){};
//! @brief Finalize.
virtual void finalize(){};
//! @brief Enable simulator command processor pump.
virtual void enableSimulatorPump() {}
//! @brief Pump simulator command processor.
virtual void pumpSimulator() {}
//! @brief Set aborted flag.
virtual void setAborted(bool aborted) {}
//! @brief Returns the max packet size supported
virtual uint32_t getMaxPacketSize();
//! @brief Peripheral accessor.
virtual UsbHidPeripheral *getPeripheral() { return (UsbHidPeripheral *)m_peripheral; }
protected:
//! @brief Flush input from device.
virtual void flushInput();
//! @brief Poll overlapped read for receiver data phase abort.
bool pollForAbortPacket();
protected:
bl_hid_report_t m_report; //!< Used for building and receiving the report.
bl_hid_report_t m_abortReport; //!< Used for received abort report.
private:
uint32_t
m_continuousReadCount; //!< Used for distinguish abort report for write-memory/receive-sb-file or read-memory
};
} // namespace blfwk
//! @}
#endif // _usb_hid_packetizer_h_
////////////////////////////////////////////////////////////////////////////////
// EOF
////////////////////////////////////////////////////////////////////////////////

View File

@ -0,0 +1,102 @@
/*
* Copyright (c) 2013-2014 Freescale Semiconductor, Inc.
* All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef _UsbHidPeripheral_h_
#define _UsbHidPeripheral_h_
#include "Peripheral.h"
#include "hidapi.h"
//! @addtogroup host_usb_hid_peripheral
//! @{
namespace blfwk
{
/*!
* @brief Represents a USB HID peripheral.
*
* Interface class for objects that provide the source for commands or sink for responses.
*/
class UsbHidPeripheral : public Peripheral
{
public:
//! @brief Constants
enum _usbhid_contants
{
kDefault_Vid = 0x15a2, //!< Freescale VID
kDefault_Pid = 0x0073, //!< PID for KL25Z48M
//kK32H_Pid = 0x0083 //!< PID for K32H (Ultra)
kK32H_Pid = 0x0052 //!< test pid (mx50)
};
public:
//! @brief Default constructor.
//!
//! Uses vendor_id = kDefault_Vid and product_id = kDefault_Pid.
UsbHidPeripheral();
//! @brief Parameterized constructor.
//!
//! @param vendor_id The Vendor ID of the USB HID device.
//! @param product_id The Product ID of the USB HID device.
//! @param serial_number The Serial Number of the USB HID device.
UsbHidPeripheral(unsigned short vendor_id, unsigned short product_id, const char *serial_number, const char *path);
//! @brief Destructor.
virtual ~UsbHidPeripheral();
//! @brief Read bytes.
//!
//! @param buffer Pointer to buffer
//! @param requestedBytes Number of bytes to read
//! @param timeoutMs Time in milliseconds to wait for read to complete.
//! @param actualBytes Number of bytes actually read.
virtual status_t read(uint8_t *buffer, uint32_t requestedBytes, uint32_t *actualBytes, uint32_t timeoutMS);
//! @brief Write bytes. This is a do nothing function implemented here to satisfy abstract base class
//! requirements. This function is not used. The write(buffer, count, timeout) function is used
//! in this child class instead of the write(buffer, cout) function declared in the base class.
virtual status_t write(const uint8_t *buffer, uint32_t byteCount) { return kStatus_Success; }
//! @brief Return peripheral Type
virtual _host_peripheral_types get_type(void) { return kHostPeripheralType_USB_HID; }
//! @brief Write bytes.
//!
//! @param buffer Pointer to buffer to write
//! @param byteCount Number of bytes to write
//! @param timeoutMs Time in milliseconds to wait for write to complete.
status_t write(const uint8_t *buffer, uint32_t byteCount, uint32_t timeoutMS);
//! @brief Return USB Vendor ID
unsigned short getVendorId() { return m_vendor_id; }
//! @brief Return USB Product ID
unsigned short getProductId() { return m_product_id; }
//! @brief Return USB Serial Number
const wchar_t *getSerialNumber() { return m_serial_number.c_str(); }
private:
//! @brief Initialize.
//!
//! Opens the HID device.
bool init();
unsigned short m_vendor_id;
unsigned short m_product_id;
std::wstring m_serial_number;
std::string m_path;
hid_device *m_device; //!< Device handle.
};
} // namespace blfwk
//! @}
#endif // _UsbHidPeripheral_h_
////////////////////////////////////////////////////////////////////////////////
// EOF
////////////////////////////////////////////////////////////////////////////////

206
src/blfwk/Value.h Normal file
View File

@ -0,0 +1,206 @@
/*
* Copyright (c) 2013-2014 Freescale Semiconductor, Inc.
* All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#if !defined(_Value_h_)
#define _Value_h_
#include <string>
#include "blfwk/stdafx.h"
#include "blfwk/int_size.h"
#include "blfwk/Blob.h"
namespace blfwk
{
/*!
* \brief Abstract base class for values of arbitrary types.
*/
class Value
{
public:
Value() {}
virtual ~Value() {}
virtual std::string getTypeName() const = 0;
virtual size_t getSize() const = 0;
};
/*!
* \brief 32-bit signed integer value.
*/
class IntegerValue : public Value
{
public:
IntegerValue()
: m_value(0)
{
}
IntegerValue(uint32_t value)
: m_value(value)
{
}
IntegerValue(const IntegerValue &other)
: m_value(other.m_value)
{
}
virtual std::string getTypeName() const { return "integer"; }
virtual size_t getSize() const { return sizeof(m_value); }
inline uint32_t getValue() const { return m_value; }
inline operator uint32_t() const { return m_value; }
inline IntegerValue &operator=(uint32_t value)
{
m_value = value;
return *this;
}
protected:
uint32_t m_value; //!< The integer value.
};
/*!
* \brief Adds a word size attribute to IntegerValue.
*
* The word size really only acts as an attribute that is carried along
* with the integer value. It doesn't affect the actual value at all.
* However, you can use the getWordSizeMask() method to mask off bits
* that should not be there.
*
* The word size defaults to a 32-bit word.
*/
class SizedIntegerValue : public IntegerValue
{
public:
SizedIntegerValue()
: IntegerValue()
, m_size(kWordSize)
{
}
SizedIntegerValue(uint32_t value, int_size_t size = kWordSize)
: IntegerValue(value)
, m_size(size)
{
}
SizedIntegerValue(uint16_t value)
: IntegerValue(value)
, m_size(kHalfWordSize)
{
}
SizedIntegerValue(uint8_t value)
: IntegerValue(value)
, m_size(kByteSize)
{
}
SizedIntegerValue(const SizedIntegerValue &other)
: IntegerValue(other)
, m_size(other.m_size)
{
}
virtual std::string getTypeName() const { return "sized integer"; }
virtual size_t getSize() const;
inline int_size_t getWordSize() const { return m_size; }
inline void setWordSize(int_size_t size) { m_size = size; }
//! \brief Returns a 32-bit mask value dependant on the word size attribute.
uint32_t getWordSizeMask() const;
//! \name Assignment operators
//! These operators set the word size as well as the integer value.
//@{
SizedIntegerValue &operator=(uint8_t value)
{
m_value = value;
m_size = kByteSize;
return *this;
}
SizedIntegerValue &operator=(uint16_t value)
{
m_value = value;
m_size = kHalfWordSize;
return *this;
}
SizedIntegerValue &operator=(uint32_t value)
{
m_value = value;
m_size = kWordSize;
return *this;
}
//@}
protected:
int_size_t m_size; //!< Size of the integer.
};
/*!
* \brief String value.
*
* Simply wraps the STL std::string class.
*/
class StringValue : public Value
{
public:
StringValue()
: m_value()
{
}
StringValue(const std::string &value)
: m_value(value)
{
}
StringValue(const std::string *value)
: m_value(*value)
{
}
StringValue(const StringValue &other)
: m_value(other.m_value)
{
}
virtual std::string getTypeName() const { return "string"; }
virtual size_t getSize() const { return m_value.size(); }
operator const char *() const { return m_value.c_str(); }
operator const std::string &() const { return m_value; }
operator std::string &() { return m_value; }
operator const std::string *() { return &m_value; }
operator std::string *() { return &m_value; }
StringValue &operator=(const StringValue &other)
{
m_value = other.m_value;
return *this;
}
StringValue &operator=(const std::string &value)
{
m_value = value;
return *this;
}
StringValue &operator=(const char *value)
{
m_value = value;
return *this;
}
protected:
std::string m_value;
};
/*!
* \brief Binary object value of arbitrary size.
*/
class BinaryValue : public Value, public Blob
{
public:
BinaryValue()
: Value()
, Blob()
{
}
virtual std::string getTypeName() const { return "binary"; }
virtual size_t getSize() const { return getLength(); }
};
}; // namespace blfwk
#endif // _Value_h_

View File

@ -0,0 +1,25 @@
/*
* Copyright (c) 2014, Freescale Semiconductor, Inc.
* All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef __BOOTLOADER_CONFIG_H__
#define __BOOTLOADER_CONFIG_H__
////////////////////////////////////////////////////////////////////////////////
// Definitions
////////////////////////////////////////////////////////////////////////////////
//
// Bootloader configuration options
//
#define BL_HAS_QSPI_MODULE (0)
#define BL_FEATURE_ENCRYPTION (0)
#endif // __BOOTLOADER_CONFIG_H__
////////////////////////////////////////////////////////////////////////////////
// EOF
////////////////////////////////////////////////////////////////////////////////

58
src/blfwk/doc/blfwk.dox Normal file
View File

@ -0,0 +1,58 @@
/*!
@defgroup blfwk Host Bootloader Framework
@brief Host Bootloader components.
@defgroup bus_pal Bus Pal Transport
@ingroup blfwk
@brief Bus Pal transport support.
@defgroup host_peripherals Peripherals
@ingroup blfwk
@brief Peripheral support.
@defgroup bus_pal_peripheral Bus Pal Peripheral
@ingroup host_peripherals
@brief Bus Pal Peripheral.
@defgroup uart_peripheral UART Peripheral
@ingroup host_peripherals
@brief UART Peripheral.
@defgroup host_usb_hid_peripheral USB-HID Peripheral
@ingroup host_peripherals
@brief USB-HID Peripheral.
@defgroup host_commands Commands
@ingroup blfwk
@brief Command support.
@defgroup host_packetizers Packetizers
@ingroup blfwk
@brief Packet creation.
@defgroup serial_packetizer Serial Packetizer
@ingroup host_packetizers
@brief Serial Packet creation.
@defgroup usb_hid_packetizer USB-HID Packetizer
@ingroup host_packetizers
@brief USB-HID Packet creation.
@defgroup logging Logging
@ingroup blfwk
@brief Logging support.
@defgroup smart_pointer Smart Pointer
@ingroup blfwk
@brief Smart pointer.
@defgroup host_error Error
@ingroup blfwk
@brief Errors.
@defgroup host_updater Updater
@ingroup blfwk
@brief Updater application support.
*/

18
src/blfwk/doc/blfwk.md Normal file
View File

@ -0,0 +1,18 @@
Host Bootloader Framework {#blfwk}
=====
Introduction
-----
The Bootloader Framework is a library of C++ classes implementing communication from a host PC to bootloader firmware running on a target device. Due to the nature of the underlying bootloader command and data protocol, the Bootloader Frameworks supports all target devices without requiring any device-specific knowledge.
Applications
-----
The Bootloader Framework library is used by the Blhost command line tool and by the KinetisFlashTool GUI firmware download tool. It can be built as a library or included as source in a PC or embedded application. The current release includes tool chains to build the library for Windows OS and Mac OS X.
Peripherals
-----
Support for the following PC peripherals is included:
- UART (COM port)
- USB-HID (using custom reports)
- Bus Pal example (UART to I2C/SPI using special hardware)

18
src/blfwk/format_string.h Normal file
View File

@ -0,0 +1,18 @@
/*
* Copyright (c) 2013-2014 Freescale Semiconductor, Inc.
* All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#if !defined(_format_string_h_)
#define _format_string_h_
#include <string>
#include <stdexcept>
/*!
* \brief Returns a formatted STL string using printf format strings.
*/
std::string format_string(const char *fmt, ...);
#endif // _format_string_h_

419
src/blfwk/hidapi.h Normal file
View File

@ -0,0 +1,419 @@
/*******************************************************
HIDAPI - Multi-Platform library for
communication with HID devices.
Alan Ott
Signal 11 Software
8/22/2009
Copyright 2009, All Rights Reserved.
At the discretion of the user of this library,
this software may be licensed under the terms of the
GNU General Public License v3, a BSD-Style license, or the
original HIDAPI license as outlined in the LICENSE.txt,
LICENSE-gpl3.txt, LICENSE-bsd.txt, and LICENSE-orig.txt
files located at the root of the source distribution.
These files may also be found in the public source
code repository located at:
http://github.com/signal11/hidapi .
********************************************************/
/** @file
* @defgroup API hidapi API
*/
#ifndef HIDAPI_H__
#define HIDAPI_H__
#include <wchar.h>
#ifdef _WIN32
#define HID_API_EXPORT __declspec(dllexport)
#define HID_API_CALL
#else
#define HID_API_EXPORT /**< API export macro */
#define HID_API_CALL /**< API call macro */
#endif
#define HID_API_EXPORT_CALL HID_API_EXPORT HID_API_CALL /**< API export and call macro*/
#ifdef __cplusplus
extern "C" {
#endif
struct hid_device_;
typedef struct hid_device_ hid_device; /**< opaque hidapi structure */
/** hidapi info structure */
struct hid_device_info
{
/** Platform-specific device path */
char *path;
/** Device Vendor ID */
unsigned short vendor_id;
/** Device Product ID */
unsigned short product_id;
/** Serial Number */
wchar_t *serial_number;
/** Device Release Number in binary-coded decimal,
also known as Device Version Number */
unsigned short release_number;
/** Manufacturer String */
wchar_t *manufacturer_string;
/** Product string */
wchar_t *product_string;
/** Usage Page for this Device/Interface
(Windows/Mac only). */
unsigned short usage_page;
/** Usage for this Device/Interface
(Windows/Mac only).*/
unsigned short usage;
/** The USB interface which this logical device
represents. Valid on both Linux implementations
in all cases, and valid on the Windows implementation
only if the device contains more than one interface. */
int interface_number;
/** Pointer to the next device */
struct hid_device_info *next;
};
/** @brief Initialize the HIDAPI library.
This function initializes the HIDAPI library. Calling it is not
strictly necessary, as it will be called automatically by
hid_enumerate() and any of the hid_open_*() functions if it is
needed. This function should be called at the beginning of
execution however, if there is a chance of HIDAPI handles
being opened by different threads simultaneously.
@ingroup API
@returns
This function returns 0 on success and -1 on error.
*/
int HID_API_EXPORT HID_API_CALL hid_init(void);
/** @brief Finalize the HIDAPI library.
This function frees all of the static data associated with
HIDAPI. It should be called at the end of execution to avoid
memory leaks.
@ingroup API
@returns
This function returns 0 on success and -1 on error.
*/
int HID_API_EXPORT HID_API_CALL hid_exit(void);
/** @brief Enumerate the HID Devices.
This function returns a linked list of all the HID devices
attached to the system which match vendor_id and product_id.
If @p vendor_id is set to 0 then any vendor matches.
If @p product_id is set to 0 then any product matches.
If @p vendor_id and @p product_id are both set to 0, then
all HID devices will be returned.
@ingroup API
@param vendor_id The Vendor ID (VID) of the types of device
to open.
@param product_id The Product ID (PID) of the types of
device to open.
@returns
This function returns a pointer to a linked list of type
struct #hid_device, containing information about the HID devices
attached to the system, or NULL in the case of failure. Free
this linked list by calling hid_free_enumeration().
*/
struct hid_device_info HID_API_EXPORT *HID_API_CALL hid_enumerate(unsigned short vendor_id, unsigned short product_id);
/** @brief Free an enumeration Linked List
This function frees a linked list created by hid_enumerate().
@ingroup API
@param devs Pointer to a list of struct_device returned from
hid_enumerate().
*/
void HID_API_EXPORT HID_API_CALL hid_free_enumeration(struct hid_device_info *devs);
/** @brief Open a HID device using a Vendor ID (VID), Product ID
(PID) and optionally a serial number.
If @p serial_number is NULL, the first device with the
specified VID and PID is opened.
@ingroup API
@param vendor_id The Vendor ID (VID) of the device to open.
@param product_id The Product ID (PID) of the device to open.
@param serial_number The Serial Number of the device to open
(Optionally NULL).
@returns
This function returns a pointer to a #hid_device object on
success or NULL on failure.
*/
HID_API_EXPORT hid_device *HID_API_CALL hid_open(unsigned short vendor_id,
unsigned short product_id,
const wchar_t *serial_number);
/** @brief Open a HID device by its path name.
The path name be determined by calling hid_enumerate(), or a
platform-specific path name can be used (eg: /dev/hidraw0 on
Linux).
@ingroup API
@param path The path name of the device to open
@returns
This function returns a pointer to a #hid_device object on
success or NULL on failure.
*/
HID_API_EXPORT hid_device *HID_API_CALL hid_open_path(const char *path);
/** @brief Write an Output report to a HID device.
The first byte of @p data[] must contain the Report ID. For
devices which only support a single report, this must be set
to 0x0. The remaining bytes contain the report data. Since
the Report ID is mandatory, calls to hid_write() will always
contain one more byte than the report contains. For example,
if a hid report is 16 bytes long, 17 bytes must be passed to
hid_write(), the Report ID (or 0x0, for devices with a
single report), followed by the report data (16 bytes). In
this example, the length passed in would be 17.
hid_write() will send the data on the first OUT endpoint, if
one exists. If it does not, it will send the data through
the Control Endpoint (Endpoint 0).
@ingroup API
@param device A device handle returned from hid_open().
@param data The data to send, including the report number as
the first byte.
@param length The length in bytes of the data to send.
@returns
This function returns the actual number of bytes written and
-1 on error.
*/
int HID_API_EXPORT HID_API_CALL hid_write(hid_device *device, const unsigned char *data, size_t length);
/** @brief Write an Output report to a HID device with timeout.
The first byte of @p data[] must contain the Report ID. For
devices which only support a single report, this must be set
to 0x0. The remaining bytes contain the report data. Since
the Report ID is mandatory, calls to hid_write() will always
contain one more byte than the report contains. For example,
if a hid report is 16 bytes long, 17 bytes must be passed to
hid_write(), the Report ID (or 0x0, for devices with a
single report), followed by the report data (16 bytes). In
this example, the length passed in would be 17.
hid_write() will send the data on the first OUT endpoint, if
one exists. If it does not, it will send the data through
the Control Endpoint (Endpoint 0).
@ingroup API
@param device A device handle returned from hid_open().
@param data The data to send, including the report number as
the first byte.
@param length The length in bytes of the data to send.
@returns
This function returns the actual number of bytes written and
-1 on error.
*/
int HID_API_EXPORT HID_API_CALL hid_write_timeout(hid_device *device,
const unsigned char *data,
size_t length,
int milliseconds);
/** @brief Read an Input report from a HID device with timeout.
Input reports are returned
to the host through the INTERRUPT IN endpoint. The first byte will
contain the Report number if the device uses numbered reports.
@ingroup API
@param device A device handle returned from hid_open().
@param data A buffer to put the read data into.
@param length The number of bytes to read. For devices with
multiple reports, make sure to read an extra byte for
the report number.
@param milliseconds timeout in milliseconds or -1 for blocking wait.
@returns
This function returns the actual number of bytes read and
-1 on error. If no packet was available to be read within
the timeout period, this function returns 0.
*/
int HID_API_EXPORT HID_API_CALL hid_read_timeout(hid_device *dev, unsigned char *data, size_t length, int milliseconds);
/** @brief Read an Input report from a HID device.
Input reports are returned
to the host through the INTERRUPT IN endpoint. The first byte will
contain the Report number if the device uses numbered reports.
@ingroup API
@param device A device handle returned from hid_open().
@param data A buffer to put the read data into.
@param length The number of bytes to read. For devices with
multiple reports, make sure to read an extra byte for
the report number.
@returns
This function returns the actual number of bytes read and
-1 on error. If no packet was available to be read and
the handle is in non-blocking mode, this function returns 0.
*/
int HID_API_EXPORT HID_API_CALL hid_read(hid_device *device, unsigned char *data, size_t length);
/** @brief Set the device handle to be non-blocking.
In non-blocking mode calls to hid_read() will return
immediately with a value of 0 if there is no data to be
read. In blocking mode, hid_read() will wait (block) until
there is data to read before returning.
Nonblocking can be turned on and off at any time.
@ingroup API
@param device A device handle returned from hid_open().
@param nonblock enable or not the nonblocking reads
- 1 to enable nonblocking
- 0 to disable nonblocking.
@returns
This function returns 0 on success and -1 on error.
*/
int HID_API_EXPORT HID_API_CALL hid_set_nonblocking(hid_device *device, int nonblock);
/** @brief Send a Feature report to the device.
Feature reports are sent over the Control endpoint as a
Set_Report transfer. The first byte of @p data[] must
contain the Report ID. For devices which only support a
single report, this must be set to 0x0. The remaining bytes
contain the report data. Since the Report ID is mandatory,
calls to hid_send_feature_report() will always contain one
more byte than the report contains. For example, if a hid
report is 16 bytes long, 17 bytes must be passed to
hid_send_feature_report(): the Report ID (or 0x0, for
devices which do not use numbered reports), followed by the
report data (16 bytes). In this example, the length passed
in would be 17.
@ingroup API
@param device A device handle returned from hid_open().
@param data The data to send, including the report number as
the first byte.
@param length The length in bytes of the data to send, including
the report number.
@returns
This function returns the actual number of bytes written and
-1 on error.
*/
int HID_API_EXPORT HID_API_CALL hid_send_feature_report(hid_device *device, const unsigned char *data, size_t length);
/** @brief Get a feature report from a HID device.
Make sure to set the first byte of @p data[] to the Report
ID of the report to be read. Make sure to allow space for
this extra byte in @p data[].
@ingroup API
@param device A device handle returned from hid_open().
@param data A buffer to put the read data into, including
the Report ID. Set the first byte of @p data[] to the
Report ID of the report to be read.
@param length The number of bytes to read, including an
extra byte for the report ID. The buffer can be longer
than the actual report.
@returns
This function returns the number of bytes read and
-1 on error.
*/
int HID_API_EXPORT HID_API_CALL hid_get_feature_report(hid_device *device, unsigned char *data, size_t length);
/** @brief Close a HID device.
@ingroup API
@param device A device handle returned from hid_open().
*/
void HID_API_EXPORT HID_API_CALL hid_close(hid_device *device);
/** @brief Get The Manufacturer String from a HID device.
@ingroup API
@param device A device handle returned from hid_open().
@param string A wide string buffer to put the data into.
@param maxlen The length of the buffer in multiples of wchar_t.
@returns
This function returns 0 on success and -1 on error.
*/
int HID_API_EXPORT_CALL hid_get_manufacturer_string(hid_device *device, wchar_t *string, size_t maxlen);
/** @brief Get The Product String from a HID device.
@ingroup API
@param device A device handle returned from hid_open().
@param string A wide string buffer to put the data into.
@param maxlen The length of the buffer in multiples of wchar_t.
@returns
This function returns 0 on success and -1 on error.
*/
int HID_API_EXPORT_CALL hid_get_product_string(hid_device *device, wchar_t *string, size_t maxlen);
/** @brief Get The Serial Number String from a HID device.
@ingroup API
@param device A device handle returned from hid_open().
@param string A wide string buffer to put the data into.
@param maxlen The length of the buffer in multiples of wchar_t.
@returns
This function returns 0 on success and -1 on error.
*/
int HID_API_EXPORT_CALL hid_get_serial_number_string(hid_device *device, wchar_t *string, size_t maxlen);
/** @brief Get a string from a HID device, based on its string index.
@ingroup API
@param device A device handle returned from hid_open().
@param string_index The index of the string to get.
@param string A wide string buffer to put the data into.
@param maxlen The length of the buffer in multiples of wchar_t.
@returns
This function returns 0 on success and -1 on error.
*/
int HID_API_EXPORT_CALL hid_get_indexed_string(hid_device *device, int string_index, wchar_t *string, size_t maxlen);
/** @brief Get a string describing the last error which occurred.
@ingroup API
@param device A device handle returned from hid_open().
@returns
This function returns a string containing the last error
which occurred or NULL if none has occurred.
*/
HID_API_EXPORT const wchar_t *HID_API_CALL hid_error(hid_device *device);
#ifdef __cplusplus
}
#endif
#endif

34
src/blfwk/host_types.h Normal file
View File

@ -0,0 +1,34 @@
/*
* Copyright (c) 2013-2014 Freescale Semiconductor, Inc.
* All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef _host_types_h_
#define _host_types_h_
#include <stdlib.h>
#include <stdio.h>
#include <stdint.h>
#include <string>
#include <vector>
#include <deque>
//! @brief An array of strings.
typedef std::vector<std::string> string_vector_t;
//! @brief An array of bytes.
typedef std::vector<unsigned char> uchar_vector_t;
//! @brief An array of uint32_t's.
typedef std::vector<uint32_t> uint32_vector_t;
//! @brief A stream of bytes.
typedef std::deque<unsigned char> uchar_deque_t;
#endif // _host_types_h_
////////////////////////////////////////////////////////////////////////////////
// EOF
////////////////////////////////////////////////////////////////////////////////

86
src/blfwk/i2c.h Normal file
View File

@ -0,0 +1,86 @@
/*
* Copyright 2020 - 2022 NXP
* All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*
*/
#ifndef __I2C_H__
#define __I2C_H__
#include <fcntl.h>
#include <linux/i2c-dev.h>
#include <linux/i2c.h>
#include <linux/types.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/ioctl.h>
#include <unistd.h>
//! @addtogroup i2c
//! @{
/*******************************************************************************
* API
******************************************************************************/
#if __cplusplus
extern "C"
{
#endif
//! @name I2C
//@{
//! @brief Configure the opened device port.
//!
//! @param fd Device port handler.
//! @param speed Device clock frequency.
//! @param address Slave device address.
int i2c_setup(int fd, uint32_t speed, uint8_t address);
//! @brief Set the transfer timeout.
//!
//! @param fd Device port handler.
//! @param miliseconds Transfer timeout.
int i2c_set_timeout(int fd, uint32_t miliseconds);
//! @brief Write bytes.
//!
//! @param fd Device port handler.
//! @param buf Pointer to buffer.
//! @param size Number of bytes to write.
int i2c_write(int fd, char *buf, int size);
//! @brief Read bytes.
//!
//! @param fd Device port handler.
//! @param buf Pointer to buffer.
//! @param size Number of bytes to read.
int i2c_read(int fd, char *buf, int size);
//! @brief Open the device port.
//!
//! @param port Device port string.
int i2c_open(char *port);
//! @brief Close the device port.
//!
//! @param fd Device port handler.
int i2c_close(int fd);
//@}
#if __cplusplus
}
#endif
//! @}
#endif //__I2C_H__
////////////////////////////////////////////////////////////////////////////////
// EOF
////////////////////////////////////////////////////////////////////////////////

27
src/blfwk/int_size.h Normal file
View File

@ -0,0 +1,27 @@
/*
* Copyright (c) 2013-2014 Freescale Semiconductor, Inc.
* All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#if !defined(_int_size_h_)
#define _int_size_h_
namespace blfwk
{
//! Supported sizes of integers.
typedef enum
{
kWordSize, //!< 32-bit word.
kHalfWordSize, //!< 16-bit half word.
kByteSize //!< 8-bit byte.
} int_size_t;
enum
{
MinEraseAlignment = 1024,
};
}; // namespace blfwk
#endif // _int_size_h_

1739
src/blfwk/json.h Normal file

File diff suppressed because it is too large Load Diff

473
src/blfwk/options.h Normal file
View File

@ -0,0 +1,473 @@
// COPY/REUSE POLICY
// =================
// Permission is hereby granted to freely copy and redistribute this
// software, provided that the author is clearly credited in all copies
// and derivations. Neither the names of the authors nor that of their
// employers may be used to endorse or promote products derived from this
// software without specific written permission.
//
//
// DISCLAIMER
// ==========
// This software is provided ``As Is'' and without any express or implied
// warranties. Neither the authors nor any of their employers (including
// any of their subsidiaries and subdivisions) are responsible for maintaining
// or supporting this software or for any consequences resulting from the
// use of this software, no matter how awful, even if they arise from flaws
// in the software.
// ****************************************************************************
// ^FILE: options.h - option parsing classes
//
// ^DESCRIPTION:
// This file defines classes used to parse command-line options.
// Options may be parsed from an array of strings, or from any structure
// for which a corresponding option-iterator exists.
//
// ^HISTORY:
// 03/06/92 Brad Appleton <bradapp@enteract.com> Created
//
// 03/23/93 Brad Appleton <bradapp@enteract.com>
// - Added OptIstreamIter class
//
// 03/08/94 Brad Appleton <bradapp@enteract.com>
// - Added Options::reset() member function
//
// 07/31/97 Brad Appleton <bradapp@enteract.com>
// - Added PARSE_POS control flag and POSITIONAL return value
//
// 04/30/06 Chris Reed
// - Updated to modern C++ and STL
// - Converted comments to doxygen style
// ^^**************************************************************************
#ifndef _options_h
#define _options_h
#ifdef USE_STDIO
#include <stdio.h>
#else
#include <iostream>
#endif
//! Abstract class to iterate through options/arguments
//!
class OptIter
{
public:
OptIter(void) {}
virtual ~OptIter(void);
//! curr() returns the current item in the iterator without
//! advancing on to the next item. If we are at the end of items
//! then NULL is returned.
virtual const char *curr(void) = 0;
//! next() advances to the next item.
virtual void next(void) = 0;
//! operator() returns the current item in the iterator and then
//! advances on to the next item. If we are at the end of items
//! then NULL is returned.
virtual const char *operator()(void);
};
//! Abstract class for a rewindable OptIter
//!
class OptIterRwd : public OptIter
{
public:
OptIterRwd(void);
virtual ~OptIterRwd(void);
virtual const char *curr(void) = 0;
virtual void next(void) = 0;
virtual const char *operator()(void) = 0;
//! rewind() resets the "current-element" to the first one in the "list"
virtual void rewind(void) = 0;
};
//! Class to iterate through an array of tokens. The array may be terminated
//! by NULL or a count containing the number of tokens may be given.
//!
class OptArgvIter : public OptIterRwd
{
private:
int ndx; // index of current arg
int ac; // arg count
const char *const *av; // arg vector
public:
OptArgvIter(const char *const argv[])
: av(argv)
, ac(-1)
, ndx(0)
{
}
OptArgvIter(int argc, const char *const argv[])
: av(argv)
, ac(argc)
, ndx(0)
{
}
virtual ~OptArgvIter(void);
virtual const char *curr(void);
virtual void next(void);
virtual const char *operator()(void);
virtual void rewind(void);
//! index returns the current index to use for argv[]
int index(void) { return ndx; }
};
//! Class to iterate through a string containing delimiter-separated tokens
//!
class OptStrTokIter : public OptIterRwd
{
private:
unsigned len; // length of token-string
const char *str; // the token-string
const char *seps; // delimiter-set (separator-characters)
const char *cur; // current token
char *tokstr; // our copy of the token-string
static const char *default_delims; // default delimiters = whitespace
public:
OptStrTokIter(const char *tokens, const char *delimiters = 0);
virtual ~OptStrTokIter(void);
virtual const char *curr(void);
virtual void next(void);
virtual const char *operator()(void);
virtual void rewind(void);
//! delimiters() with NO arguments returns the current set of delimiters,
//! If an argument is given then it is used as the new set of delimiters.
const char *delimiters(void) { return seps; }
void delimiters(const char *delims) { seps = (delims) ? delims : default_delims; }
};
//! OptIstreamIter is a class for iterating over arguments that come
//! from an input stream. Each line of the input stream is considered
//! to be a set of white-space separated tokens. If the the first
//! non-white character on a line is '#' ('!' for VMS systems) then
//! the line is considered a comment and is ignored.
//!
//! \note If a line is more than 1022 characters in length then we
//! treat it as if it were several lines of length 1022 or less.
//!
//! \note The string tokens returned by this iterator are pointers
//! to temporary buffers which may not necessarily stick around
//! for too long after the call to curr() or operator(), hence
//! if you need the string value to persist - you will need to
//! make a copy.
//!
class OptIstreamIter : public OptIter
{
private:
std::istream &is;
OptStrTokIter *tok_iter;
void fill(void);
public:
static const unsigned MAX_LINE_LEN;
OptIstreamIter(std::istream &input);
virtual ~OptIstreamIter(void);
virtual const char *curr(void);
virtual void next(void);
virtual const char *operator()(void);
};
//! \brief parse command-line options
//!
//! \section Synopsis
//! \code
//! #include <options.h>
//!
//! Options opts(cmdname, optv);
//! char cmdname[], *optv[];
//! \endcode
//! \section Description
//! The Options constructor expects a command-name (usually argv[0]) and
//! a pointer to an array of strings. The last element in this array MUST
//! be NULL. Each non-NULL string in the array must have the following format:
//!
//! The 1st character must be the option-name ('c' for a -c option).
//!
//! The 2nd character must be one of '|', '?', ':', '*', or '+'.
//! '|' -- indicates that the option takes NO argument;
//! '?' -- indicates that the option takes an OPTIONAL argument;
//! ':' -- indicates that the option takes a REQUIRED argument;
//! '*' -- indicates that the option takes 0 or more arguments;
//! '+' -- indicates that the option takes 1 or more arguments;
//!
//! The remainder of the string must be the long-option name.
//!
//! If desired, the long-option name may be followed by one or more
//! spaces and then by the name of the option value. This name will
//! be used when printing usage messages. If the option-value-name
//! is not given then the string "<value>" will be used in usage
//! messages.
//!
//! One may use a space to indicate that a particular option does not
//! have a corresponding long-option. For example, "c: " (or "c:")
//! means the -c option takes a value & has NO corresponding long-option.
//!
//! To specify a long-option that has no corresponding single-character
//! option is a bit trickier: Options::operator() still needs an "option-
//! character" to return when that option is matched. One may use a whitespace
//! character or a non-printable character as the single-character option
//! in such a case. (hence " |hello" would only match "--hello").
//!
//! \section Exceptions Exceptions to the above
//! If the 1st character of the string is '-', then the rest of the
//! string must correspond to the above format, and the option is
//! considered to be a hidden-option. This means it will be parsed
//! when actually matching options from the command-line, but will
//! NOT show-up if a usage message is printed using the usage() member
//! function. Such an example might be "-h|hidden". If you want to
//! use any "dummy" options (options that are not parsed, but that
//! to show up in the usage message), you can specify them along with
//! any positional parameters to the usage() member function.
//!
//! If the 2nd character of the string is '\0' then it is assumed
//! that there is no corresponding long-option and that the option
//! takes no argument (hence "f", and "f| " are equivalent).
//!
//! \code
//! const char * optv[] = {
//! "c:count <number>",
//! "s?str <string>",
//! "x",
//! " |hello",
//! "g+groups <newsgroup>",
//! NULL
//! } ;
//! \endcode
//! optv[] now corresponds to the following:
//!
//! usage: cmdname [-c|--count <number>] [-s|--str [<string>]]
//! [-x] [--hello] [-g|--groups <newsgroup> ...]
//!
//! Long-option names are matched case-insensitive and only a unique prefix
//! of the name needs to be specified.
//!
//! Option-name characters are case-sensitive!
//!
//! \section Caveat
//! Because of the way in which multi-valued options and options with optional
//! values are handled, it is NOT possible to supply a value to an option in
//! a separate argument (different argv[] element) if the value is OPTIONAL
//! and begins with a '-'. What this means is that if an option "-s" takes an
//! optional value value and you wish to supply a value of "-foo" then you must
//! specify this on the command-line as "-s-foo" instead of "-s -foo" because
//! "-s -foo" will be considered to be two separate sets of options.
//!
//! A multi-valued option is terminated by another option or by the end-of
//! options. The following are all equivalent (if "-l" is a multi-valued
//! option and "-x" is an option that takes no value):
//!
//! cmdname -x -l item1 item2 item3 -- arg1 arg2 arg3
//! cmdname -x -litem1 -litem2 -litem3 -- arg1 arg2 arg3
//! cmdname -l item1 item2 item3 -x arg1 arg2 arg3
//!
//!
//! \code
//! #include <options.h>
//!
//! static const char * optv[] = {
//! "H|help",
//! "c:count <number>",
//! "s?str <string>",
//! "x",
//! " |hello",
//! "g+groups <newsgroup>",
//! NULL
//! } ;
//!
//! main(int argc, char * argv[]) {
//! int optchar;
//! const char * optarg;
//! const char * str = "default_string";
//! int count = 0, xflag = 0, hello = 0;
//! int errors = 0, ngroups = 0;
//!
//! Options opts(*argv, optv);
//! OptArgvIter iter(--argc, ++argv);
//!
//! while( optchar = opts(iter, optarg) ) {
//! switch (optchar) {
//! case 'H' :
//! opts.usage(cout, "files ...");
//! exit(0);
//! break;
//! case 'g' :
//! ++ngroups; break; //! the groupname is in "optarg"
//! case 's' :
//! str = optarg; break;
//! case 'x' :
//! ++xflag; break;
//! case ' ' :
//! ++hello; break;
//! case 'c' :
//! if (optarg == NULL) ++errors;
//! else count = (int) atol(optarg);
//! break;
//! default : ++errors; break;
//! } //!switch
//! }
//!
//! if (errors || (iter.index() == argc)) {
//! if (! errors) {
//! cerr << opts.name() << ": no filenames given." << endl ;
//! }
//! opts.usage(cerr, "files ...");
//! exit(1);
//! }
//!
//! cout << "xflag=" << ((xflag) ? "ON" : "OFF") << endl
//! << "hello=" << ((hello) ? "YES" : "NO") << endl
//! << "count=" << count << endl
//! << "str=\"" << ((str) ? str : "No value given!") << "\"" << endl
//! << "ngroups=" << ngroups << endl ;
//!
//! if (iter.index() < argc) {
//! cout << "files=" ;
//! for (int i = iter.index() ; i < argc ; i++) {
//! cout << "\"" << argv[i] << "\" " ;
//! }
//! cout << endl ;
//! }
//! }
//! \endcode
class Options
{
private:
unsigned explicit_end : 1; //!< were we terminated because of "--"?
unsigned optctrls : 7; //!< control settings (a set of OptCtrl masks)
const char *const *optvec; //!< vector of option-specifications (last=NULL)
const char *nextchar; //!< next option-character to process
const char *listopt; //!< last list-option we matched
const char *cmdname; //!< name of the command
void check_syntax(void) const;
const char *match_opt(char opt, int ignore_case = 0) const;
const char *match_longopt(const char *opt, int len, int &ambiguous) const;
int parse_opt(OptIter &iter, const char *&optarg);
int parse_longopt(OptIter &iter, const char *&optarg);
public:
enum OptCtrl
{
DEFAULT = 0x00, //!< Default setting
ANYCASE = 0x01, //!< Ignore case when matching short-options
QUIET = 0x02, //!< Dont print error messages
PLUS = 0x04, //!< Allow "+" as a long-option prefix
SHORT_ONLY = 0x08, //!< Dont accept long-options
LONG_ONLY = 0x10, //!< Dont accept short-options
//!< (also allows "-" as a long-option prefix).
NOGUESSING = 0x20, //!< Normally, when we see a short (long) option
//!< on the command line that doesnt match any
//!< known short (long) options, then we try to
//!< "guess" by seeing if it will match any known
//!< long (short) option. Setting this mask prevents
//!< this "guessing" from occurring.
PARSE_POS = 0x40 //!< By default, Options will not present positional
//!< command-line arguments to the user and will
//!< instead stop parsing when the first positonal
//!< argument has been encountered. If this flag
//!< is given, Options will present positional
//!< arguments to the user with a return code of
//!< POSITIONAL; ENDOPTS will be returned only
//!< when the end of the argument list is reached.
};
//! Error return values for operator()
//!
enum OptRC
{
ENDOPTS = 0,
BADCHAR = -1,
BADKWD = -2,
AMBIGUOUS = -3,
POSITIONAL = -4
};
Options(const char *name, const char *const optv[]);
virtual ~Options(void);
//! name() returns the command name
const char *name(void) const { return cmdname; }
//! ctrls() (with no arguments) returns the existing control settings
unsigned ctrls(void) const { return optctrls; }
//! ctrls() (with 1 argument) sets new control settings
void ctrls(unsigned newctrls) { optctrls = newctrls; }
//! reset for another pass to parse for options
void reset(void) { nextchar = listopt = NULL; }
//! usage() prints options usage (followed by any positional arguments
//! listed in the parameter "positionals") on the given outstream
void usage(std::ostream &os, const char *positionals) const;
//! operator() iterates through the arguments as necessary (using the
//! given iterator) and returns the character value of the option
//! (or long-option) that it matched. If the option has a value
//! then the value given may be found in optarg (otherwise optarg
//! will be NULL).
//!
//! 0 is returned upon end-of-options. At this point, "iter" may
//! be used to process any remaining positional parameters. If the
//! PARSE_POS control-flag is set then 0 is returned only when all
//! arguments in "iter" have been exhausted.
//!
//! If an invalid option is found then BADCHAR is returned and *optarg
//! is the unrecognized option character.
//!
//! If an invalid long-option is found then BADKWD is returned and optarg
//! points to the bad long-option.
//!
//! If an ambiguous long-option is found then AMBIGUOUS is returned and
//! optarg points to the ambiguous long-option.
//!
//! If the PARSE_POS control-flag is set then POSITIONAL is returned
//! when a positional argument is encountered and optarg points to
//! the positonal argument (and "iter" is advanced to the next argument
//! in the iterator).
//!
//! Unless Options::QUIET is used, missing option-arguments and
//! invalid options (and the like) will automatically cause error
//! messages to be issued to cerr.
int operator()(OptIter &iter, const char *&optarg);
//! Call this member function after operator() has returned 0
//! if you want to know whether or not options were explicitly
//! terminated because "--" appeared on the command-line.
//!
int explicit_endopts() const { return explicit_end; }
};
#endif /* _options_h */

180
src/blfwk/rijndael.h Normal file
View File

@ -0,0 +1,180 @@
#ifndef _RIJNDAEL_H_
#define _RIJNDAEL_H_
//
// File : rijndael.h
// Creation date : Sun Nov 5 2000 03:21:05 CEST
// Author : Szymon Stefanek (stefanek@tin.it)
//
// Another implementation of the Rijndael cipher.
// This is intended to be an easily usable library file.
// This code is public domain.
// Based on the Vincent Rijmen and K.U.Leuven implementation 2.4.
//
//
// Original Copyright notice:
//
// rijndael-alg-fst.c v2.4 April '2000
// rijndael-alg-fst.h
// rijndael-api-fst.c
// rijndael-api-fst.h
//
// Optimised ANSI C code
//
// authors: v1.0: Antoon Bosselaers
// v2.0: Vincent Rijmen, K.U.Leuven
// v2.3: Paulo Barreto
// v2.4: Vincent Rijmen, K.U.Leuven
//
// This code is placed in the public domain.
//
//
// This implementation works on 128 , 192 , 256 bit keys
// and on 128 bit blocks
//
//
// Example of usage:
//
// // Input data
// unsigned char key[32]; // The key
// initializeYour256BitKey(); // Obviously initialized with sth
// const unsigned char * plainText = getYourPlainText(); // Your plain text
// int plainTextLen = strlen(plainText); // Plain text length
//
// // Encrypting
// Rijndael rin;
// unsigned char output[plainTextLen + 16];
//
// rin.init(Rijndael::CBC,Rijndael::Encrypt,key,Rijndael::Key32Bytes);
// // It is a good idea to check the error code
// int len = rin.padEncrypt(plainText,len,output);
// if(len >= 0)useYourEncryptedText();
// else encryptError(len);
//
// // Decrypting: we can reuse the same object
// unsigned char output2[len];
// rin.init(Rijndael::CBC,Rijndael::Decrypt,key,Rijndael::Key32Bytes));
// len = rin.padDecrypt(output,len,output2);
// if(len >= 0)useYourDecryptedText();
// else decryptError(len);
//
#include <stdint.h>
#define _MAX_KEY_COLUMNS (256 / 32)
#define _MAX_ROUNDS 14
#define MAX_IV_SIZE 16
// We assume that unsigned int is 32 bits long....
// typedef unsigned char uint8_t;
// typedef unsigned int uint32_t;
// typedef unsigned short uint16_t;
// Error codes
#define RIJNDAEL_SUCCESS 0
#define RIJNDAEL_UNSUPPORTED_MODE -1
#define RIJNDAEL_UNSUPPORTED_DIRECTION -2
#define RIJNDAEL_UNSUPPORTED_KEY_LENGTH -3
#define RIJNDAEL_BAD_KEY -4
#define RIJNDAEL_NOT_INITIALIZED -5
#define RIJNDAEL_BAD_DIRECTION -6
#define RIJNDAEL_CORRUPTED_DATA -7
class Rijndael
{
public:
enum Direction
{
Encrypt,
Decrypt
};
enum Mode
{
ECB,
CBC,
CFB1
};
enum KeyLength
{
Key16Bytes,
Key24Bytes,
Key32Bytes
};
//
// Creates a Rijndael cipher object
// You have to call init() before you can encrypt or decrypt stuff
//
Rijndael();
~Rijndael();
protected:
// Internal stuff
enum State
{
Valid,
Invalid
};
State m_state;
Mode m_mode;
Direction m_direction;
uint8_t m_initVector[MAX_IV_SIZE];
uint32_t m_uRounds;
uint8_t m_expandedKey[_MAX_ROUNDS + 1][4][4];
public:
//////////////////////////////////////////////////////////////////////////////////////////
// API
//////////////////////////////////////////////////////////////////////////////////////////
// init(): Initializes the crypt session
// Returns RIJNDAEL_SUCCESS or an error code
// mode : Rijndael::ECB, Rijndael::CBC or Rijndael::CFB1
// You have to use the same mode for encrypting and decrypting
// dir : Rijndael::Encrypt or Rijndael::Decrypt
// A cipher instance works only in one direction
// (Well , it could be easily modified to work in both
// directions with a single init() call, but it looks
// useless to me...anyway , it is a matter of generating
// two expanded keys)
// key : array of unsigned octets , it can be 16 , 24 or 32 bytes long
// this CAN be binary data (it is not expected to be null terminated)
// keyLen : Rijndael::Key16Bytes , Rijndael::Key24Bytes or Rijndael::Key32Bytes
// initVector: initialization vector, you will usually use 0 here
int init(Mode mode, Direction dir, const uint8_t *key, KeyLength keyLen, uint8_t *initVector = 0);
// Encrypts the input array (can be binary data)
// The input array length must be a multiple of 16 bytes, the remaining part
// is DISCARDED.
// so it actually encrypts inputLen / 128 blocks of input and puts it in outBuffer
// Input len is in BITS!
// outBuffer must be at least inputLen / 8 bytes long.
// Returns the encrypted buffer length in BITS or an error code < 0 in case of error
int blockEncrypt(const uint8_t *input, int inputLen, uint8_t *outBuffer);
// Encrypts the input array (can be binary data)
// The input array can be any length , it is automatically padded on a 16 byte boundary.
// Input len is in BYTES!
// outBuffer must be at least (inputLen + 16) bytes long
// Returns the encrypted buffer length in BYTES or an error code < 0 in case of error
int padEncrypt(const uint8_t *input, int inputOctets, uint8_t *outBuffer);
// Decrypts the input vector
// Input len is in BITS!
// outBuffer must be at least inputLen / 8 bytes long
// Returns the decrypted buffer length in BITS and an error code < 0 in case of error
int blockDecrypt(const uint8_t *input, int inputLen, uint8_t *outBuffer);
// Decrypts the input vector
// Input len is in BYTES!
// outBuffer must be at least inputLen bytes long
// Returns the decrypted buffer length in BYTES and an error code < 0 in case of error
int padDecrypt(const uint8_t *input, int inputOctets, uint8_t *outBuffer);
protected:
void keySched(uint8_t key[_MAX_KEY_COLUMNS][4]);
void keyEncToDec();
void encrypt(const uint8_t a[16], uint8_t b[16]);
void decrypt(const uint8_t a[16], uint8_t b[16]);
};
#endif // _RIJNDAEL_H_

70
src/blfwk/serial.h Normal file
View File

@ -0,0 +1,70 @@
/*
* This file is part of the Bus Pirate project (http://code.google.com/p/the-bus-pirate/).
*
* Written and maintained by the Bus Pirate project and http://dangerousprototypes.com
*
* To the extent possible under law, the project has
* waived all copyright and related or neighboring rights to Bus Pirate. This
* work is published from United States.
*
* For details see: http://creativecommons.org/publicdomain/zero/1.0/.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
*/
/*
* OS independent serial interface
*
* Heavily based on Pirate-Loader:
* http://the-bus-pirate.googlecode.com/svn/trunk/bootloader-v4/pirate-loader/source/pirate-loader.c
*
*/
#ifndef MYSERIAL_H_
#define MYSERIAL_H_
#ifdef MACOSX
#include <IOKit/serial/ioss.h>
#include <sys/ioctl.h>
#define B1500000 1500000
#define B1000000 1000000
#define B921600 921600
#endif
#include <stdint.h>
#ifdef WIN32
#include <windows.h>
#include <time.h>
#define B115200 115200
#define B921600 921600
typedef long speed_t;
#else
#include <unistd.h>
#include <termios.h>
#include <sys/select.h>
#include <sys/types.h>
#include <sys/time.h>
#endif
#if __cplusplus
extern "C" {
#endif
int serial_setup(int fd, speed_t speed);
int serial_set_read_timeout(int fd, uint32_t timeoutMs);
int serial_write(int fd, char *buf, int size);
int serial_read(int fd, char *buf, int size);
int serial_open(char *port);
int serial_close(int fd);
#if __cplusplus
}
#endif
#endif

215
src/blfwk/smart_ptr.h Normal file
View File

@ -0,0 +1,215 @@
/*
* Copyright (c) 2013-2014 Freescale Semiconductor, Inc.
* All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#if !defined(_smart_ptr_h_)
#define _smart_ptr_h_
//! @addtogroup smart_pointer
//! @{
/*!
* \brief Simple, standard smart pointer class.
*
* This class only supports the single-owner paradigm.
*/
template <typename T>
class smart_ptr
{
public:
typedef T data_type;
typedef T *ptr_type;
typedef const T *const_ptr_type;
typedef T &ref_type;
typedef const T &const_ref_type;
//! Default constuctor. Initialises with no pointer set.
smart_ptr()
: _p(0)
{
}
//! This constructor takes a pointer to the object to be deleted.
smart_ptr(ptr_type p)
: _p(p)
{
}
//! Destructor. If an object (pointer) has been set, it will be deleted.
//! Deletes the object using safe_delete().
virtual ~smart_ptr() { safe_delete(); }
//! Return the current pointer value.
ptr_type get() { return _p; }
//! Return the const form of the current pointer value.
const_ptr_type get() const { return _p; }
//! Change the pointer value, or set if if the default constructor was used.
//! If a pointer had previously been associated with the object, and \a p is
//! different than that previous pointer, it will be deleted before taking
//! ownership of \a p. If this is not desired, call reset() beforehand.
void set(ptr_type p)
{
if (_p && p != _p)
{
safe_delete();
}
_p = p;
}
//! Dissociates any previously set pointer value without deleting it.
void reset() { _p = 0; }
//! Dissociates a previously set pointer value, deleting it at the same time.
void clear() { safe_delete(); }
//! Forces immediate deletion of the object. If you are planning on using
//! this method, think about just using a normal pointer. It probably makes
//! more sense.
virtual void safe_delete()
{
if (_p)
{
delete _p;
_p = 0;
}
}
//! \name Operators
//@{
//! Makes the object transparent as the template type.
operator ptr_type() { return _p; }
//! Const version of the pointer operator.
operator const_ptr_type() const { return _p; }
//! Makes the object transparent as a reference of the template type.
operator ref_type() { return *_p; }
//! Const version of the reference operator.
operator const_ref_type() const { return *_p; }
//! Returns a boolean indicating whether the object has a pointer set or not.
operator bool() const { return _p != 0; }
//! To allow setting the pointer directly. Equivalent to a call to set().
smart_ptr<T> &operator=(const_ptr_type p)
{
set(const_cast<ptr_type>(p));
return *this;
}
//! Another operator to allow you to treat the object just like a pointer.
ptr_type operator->() { return _p; }
//! Another operator to allow you to treat the object just like a pointer.
const_ptr_type operator->() const { return _p; }
// //! Pointer dereferencing operator.
// ref_type operator * () const { return *_p; }
//
// //! Const version of the pointer dereference operator.
// const_ref_type operator * () const { return *_p; }
//@}
protected:
ptr_type _p; //!< The wrapped pointer.
};
/*!
* \brief Simple, standard smart pointer class that uses the array delete operator.
*
* This class only supports the single-owner paradigm.
*
* This is almost entirely a copy of smart_ptr since the final C++ specification
* does not allow template subclass members to access members of the parent that
* do not depend on the template parameter.
*/
template <typename T>
class smart_array_ptr
{
public:
typedef T data_type;
typedef T *ptr_type;
typedef const T *const_ptr_type;
typedef T &ref_type;
typedef const T &const_ref_type;
//! Default constuctor. Initialises with no pointer set.
smart_array_ptr()
: _p(0)
{
}
//! This constructor takes a pointer to the object to be deleted.
smart_array_ptr(ptr_type p)
: _p(p)
{
}
//! Destructor. If an array has been set, it will be deleted.
//! Deletes the array using safe_delete().
virtual ~smart_array_ptr() { safe_delete(); }
//! Return the current pointer value.
ptr_type get() { return _p; }
//! Return the const form of the current pointer value.
const_ptr_type get() const { return _p; }
//! Change the pointer value, or set if if the default constructor was used.
//! If a pointer had previously been associated with the object, and \a p is
//! different than that previous pointer, it will be deleted before taking
//! ownership of \a p. If this is not desired, call reset() beforehand.
void set(ptr_type p)
{
if (_p && p != _p)
{
safe_delete();
}
_p = p;
}
//! Dissociates any previously set pointer value without deleting it.
void reset() { _p = 0; }
//! Dissociates a previously set pointer value, deleting it at the same time.
void clear() { safe_delete(); }
//! Forces immediate deletion of the object. If you are planning on using
//! this method, think about just using a normal pointer. It probably makes
//! more sense.
virtual void safe_delete()
{
if (_p)
{
delete[] _p;
_p = 0;
}
}
//! \name Operators
//@{
//! Makes the object transparent as the template type.
operator ptr_type() { return _p; }
//! Const version of the pointer operator.
operator const_ptr_type() const { return _p; }
//! Makes the object transparent as a reference of the template type.
operator ref_type() { return *_p; }
//! Const version of the reference operator.
operator const_ref_type() const { return *_p; }
//! Returns a boolean indicating whether the object has a pointer set or not.
operator bool() const { return _p != 0; }
//! To allow setting the pointer directly. Equivalent to a call to set().
smart_array_ptr<T> &operator=(const_ptr_type p)
{
set(const_cast<ptr_type>(p));
return *this;
}
//! Another operator to allow you to treat the object just like a pointer.
ptr_type operator->() { return _p; }
//! Another operator to allow you to treat the object just like a pointer.
const_ptr_type operator->() const { return _p; }
//! Indexing operator.
ref_type operator[](unsigned index) { return _p[index]; }
//! Indexing operator.
const_ref_type operator[](unsigned index) const { return _p[index]; }
//@}
protected:
ptr_type _p; //!< The wrapped pointer.
};
//! @}
#endif // _smart_ptr_h_

86
src/blfwk/spi.h Normal file
View File

@ -0,0 +1,86 @@
/*
* Copyright 2020 - 2022 NXP
* All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*
*/
#ifndef __SPI_H__
#define __SPI_H__
#include <fcntl.h>
#include <linux/spi/spidev.h>
#include <linux/types.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/ioctl.h>
#include <unistd.h>
//! @addtogroup spi
//! @{
/*******************************************************************************
* API
******************************************************************************/
#if __cplusplus
extern "C"
{
#endif
//! @name SPI
//@{
//! @brief Configure the opened device port.
//!
//! @param fd Device port handler.
//! @param speed Device clock frequency.
//! @param mode Polarity and phase mode.
//! @param bits_per_word Transfer size.
int spi_setup(int fd, uint32_t speed, uint32_t mode, uint32_t bits_per_word);
//! @brief Set the transfer timeout.
//!
//! @param fd Device port handler.
//! @param miliseconds Transfer timeout.
int spi_set_timeout(int fd, uint32_t miliseconds);
//! @brief Write bytes.
//!
//! @param fd Device port handler.
//! @param buf Pointer to buffer.
//! @param size Number of bytes to write.
int spi_write(int fd, char *buf, int size);
//! @brief Read bytes.
//!
//! @param fd Device port handler.
//! @param buf Pointer to buffer.
//! @param size Number of bytes to read.
int spi_read(int fd, char *buf, int size);
//! @brief Open the device port.
//!
//! @param port Device port string.
int spi_open(char *port);
//! @brief Close the device port.
//!
//! @param fd Device port handler.
int spi_close(int fd);
//@}
#if __cplusplus
}
#endif
//! @}
#endif //__SPI_H__
////////////////////////////////////////////////////////////////////////////////
// EOF
////////////////////////////////////////////////////////////////////////////////

View File

@ -0,0 +1,76 @@
/*
* File: AESCounter.cpp
*
* Copyright (c) Freescale Semiconductor, Inc. All rights reserved.
* See included license file for license details.
*/
#include "blfwk/AESCounter.h"
#include <stdexcept>
#include "blfwk/smart_ptr.h"
#include "blfwk/HexValues.h"
#include <ctype.h>
//! The data from the stream is expected to be hex encoded. Each two characters
//! from the stream encode a single result byte. All non-hexadecimal characters
//! are ignored, including newlines. Every two hexadecimal characters form
//! an encoded byte. This is true even if the two characters representing the
//! upper and lower nibbles are separated by whitespace or other characters.
//!
//! \post The stream read head is left pointing just after the last encoded byte.
//!
//! \param stream Input stream to read from.
//! \param bytes Number of encoded bytes to read. This is the number of \e
//! result bytes, not the count of bytes to read from the stream.
//! \param[out] buffer Pointer to the buffer where decoded data is written.
//!
//! \exception std::runtime_error This exception will be thrown if less
//! data than required is available from \a stream, or if some other
//! error occurs while reading from \a stream.
void AESCounterBase::_readFromStream(std::istream &stream, unsigned bytes, uint8_t *buffer)
{
char temp[2];
char c;
char n = 0;
while (bytes)
{
if (stream.get(c).fail())
{
throw std::runtime_error("not enough data in stream");
}
if (isHexDigit(c))
{
temp[n++] = c;
if (n == 2)
{
*buffer++ = hexByteToInt(temp);
bytes--;
n = 0;
}
}
}
}
//! Counter data is written to \a stream as a sequence of hex encoded octets, each two
//! characters long. No spaces or newlines are inserted between the encoded octets
//! or at the end of the sequence.
//!
//! \exception std::runtime_error Thrown if the \a stream reports an error while
//! writing the key data.
void AESCounterBase::_writeToStream(std::ostream &stream, unsigned bytes, const uint8_t *buffer) const
{
const char hexChars[] = "0123456789ABCDEF";
while (bytes--)
{
uint8_t thisByte = *buffer++;
char byteString[2];
byteString[0] = hexChars[(thisByte & 0xf0) >> 4];
byteString[1] = hexChars[thisByte & 0x0f];
if (stream.write(byteString, 2).bad())
{
throw std::runtime_error("error while writing to stream");
}
}
}

76
src/blfwk/src/AESKey.cpp Normal file
View File

@ -0,0 +1,76 @@
/*
* File: AESKey.cpp
*
* Copyright (c) Freescale Semiconductor, Inc. All rights reserved.
* See included license file for license details.
*/
#include "blfwk/AESKey.h"
#include <stdexcept>
#include "blfwk/smart_ptr.h"
#include "blfwk/HexValues.h"
#include <ctype.h>
//! The data from the stream is expected to be hex encoded. Each two characters
//! from the stream encode a single result byte. All non-hexadecimal characters
//! are ignored, including newlines. Every two hexadecimal characters form
//! an encoded byte. This is true even if the two characters representing the
//! upper and lower nibbles are separated by whitespace or other characters.
//!
//! \post The stream read head is left pointing just after the last encoded byte.
//!
//! \param stream Input stream to read from.
//! \param bytes Number of encoded bytes to read. This is the number of \e
//! result bytes, not the count of bytes to read from the stream.
//! \param[out] buffer Pointer to the buffer where decoded data is written.
//!
//! \exception std::runtime_error This exception will be thrown if less
//! data than required is available from \a stream, or if some other
//! error occurs while reading from \a stream.
void AESKeyBase::_readFromStream(std::istream &stream, unsigned bytes, uint8_t *buffer) const
{
char temp[2];
char c;
char n = 0;
while (bytes)
{
if (stream.get(c).fail())
{
throw std::runtime_error("not enough data in stream");
}
if (isHexDigit(c))
{
temp[n++] = c;
if (n == 2)
{
*buffer++ = hexByteToInt(temp);
bytes--;
n = 0;
}
}
}
}
//! Key data is written to \a stream as a sequence of hex encoded octets, each two
//! characters long. No spaces or newlines are inserted between the encoded octets
//! or at the end of the sequence.
//!
//! \exception std::runtime_error Thrown if the \a stream reports an error while
//! writing the key data.
void AESKeyBase::_writeToStream(std::ostream &stream, unsigned bytes, const uint8_t *buffer) const
{
const char hexChars[] = "0123456789ABCDEF";
while (bytes--)
{
uint8_t thisByte = *buffer++;
char byteString[2];
byteString[0] = hexChars[(thisByte & 0xf0) >> 4];
byteString[1] = hexChars[thisByte & 0x0f];
if (stream.write(byteString, 2).bad())
{
throw std::runtime_error("error while writing to stream");
}
}
}

122
src/blfwk/src/Blob.cpp Normal file
View File

@ -0,0 +1,122 @@
/*
* File: Blob.cpp
*
* Copyright (c) Freescale Semiconductor, Inc. All rights reserved.
* See included license file for license details.
*/
#include "blfwk/Blob.h"
#include <stdexcept>
#include <stdlib.h>
#include <string.h>
Blob::Blob()
: m_data(0)
, m_length(0)
{
}
//! Makes a local copy of the \a data argument.
//!
Blob::Blob(const uint8_t *data, unsigned length)
: m_data(0)
, m_length(length)
{
m_data = reinterpret_cast<uint8_t *>(malloc(length));
memcpy(m_data, data, length);
}
//! Makes a local copy of the data owned by \a other.
//!
Blob::Blob(const Blob &other)
: m_data(0)
, m_length(other.m_length)
{
m_data = reinterpret_cast<uint8_t *>(malloc(m_length));
memcpy(m_data, other.m_data, m_length);
}
//! Disposes of the binary data associated with this object.
Blob::~Blob()
{
if (m_data)
{
free(m_data);
}
}
//! Copies \a data onto the blob's data. The blob does not assume ownership
//! of \a data.
//!
//! \param data Pointer to a buffer containing the data which will be copied
//! into the blob.
//! \param length Number of bytes pointed to by \a data.
void Blob::setData(const uint8_t *data, unsigned length)
{
setLength(length);
memcpy(m_data, data, length);
}
//! Sets the #m_length member variable to \a length and resizes #m_data to
//! the new length. The contents of #m_data past any previous contents are undefined.
//! If the new \a length is 0 then the data will be freed and a subsequent call
//! to getData() will return NULL.
//!
//! \param length New length of the blob's data in bytes.
void Blob::setLength(unsigned length)
{
if (length == 0)
{
clear();
return;
}
// Allocate new block.
if (!m_data)
{
m_data = reinterpret_cast<uint8_t *>(malloc(length));
if (!m_data)
{
throw std::runtime_error("failed to allocate memory");
}
}
// Reallocate previous block.
else
{
void *newBlob = realloc(m_data, length);
if (!newBlob)
{
throw std::runtime_error("failed to reallocate memory");
}
m_data = reinterpret_cast<uint8_t *>(newBlob);
}
// Set length.
m_length = length;
}
void Blob::append(const uint8_t *newData, unsigned newDataLength)
{
unsigned oldLength = m_length;
setLength(m_length + newDataLength);
memcpy(m_data + oldLength, newData, newDataLength);
}
void Blob::clear()
{
if (m_data)
{
free(m_data);
m_data = NULL;
}
m_length = 0;
}
void Blob::relinquish()
{
m_data = NULL;
m_length = 0;
}

View File

@ -0,0 +1,359 @@
/*
* Copyright (c) 2013-2014 Freescale Semiconductor, Inc.
* Copyright 2015-2020 NXP
* All rights reserved.
*
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include "blfwk/Bootloader.h"
#include "blfwk/BusPalPeripheral.h"
#include "blfwk/LpcUsbSioPeripheral.h"
#include "blfwk/SerialPacketizer.h"
#include "blfwk/UartPeripheral.h"
#if defined(LINUX) && defined(__ARM__)
#include "blfwk/I2cPeripheral.h"
#include "blfwk/SpiPeripheral.h"
#endif
#include "blfwk/UsbHidPacketizer.h"
#include "blfwk/UsbHidPeripheral.h"
#include "blfwk/format_string.h"
#include "blfwk/json.h"
#include "blfwk/utils.h"
using namespace blfwk;
using namespace std;
////////////////////////////////////////////////////////////////////////////////
// Definitions
////////////////////////////////////////////////////////////////////////////////
enum
{
kBuspalReadRetries = 3
};
////////////////////////////////////////////////////////////////////////////////
// Code
////////////////////////////////////////////////////////////////////////////////
// See host_bootloader.h for documentation of this method.
Bootloader::Bootloader()
: m_hostPacketizer(NULL)
, m_logger(NULL)
{
// create logger instance
if (Log::getLogger() == NULL)
{
this->m_logger = new FileLogger("bootloader.log");
this->m_logger->setFilterLevel(Logger::kDebug2 /*Logger::kInfo*/);
Log::setLogger(this->m_logger);
}
}
// See host_bootloader.h for documentation of this method.
Bootloader::Bootloader(const Peripheral::PeripheralConfigData &config)
: m_hostPacketizer(NULL)
, m_logger(NULL)
{
// create logger instance
if (Log::getLogger() == NULL)
{
this->m_logger = new FileLogger("bootloader.log");
this->m_logger->setFilterLevel(Logger::kDebug2 /*Logger::kInfo*/);
Log::setLogger(this->m_logger);
}
switch (config.peripheralType)
{
case Peripheral::kHostPeripheralType_UART:
{
UartPeripheral *peripheral = new UartPeripheral(config.comPortName.c_str(), config.comPortSpeed);
m_hostPacketizer = new SerialPacketizer(peripheral, config.packetTimeoutMs);
if (config.ping)
{
// Send initial ping.
try
{
ping(0, 0, config.comPortSpeed, NULL);
}
catch (const std::exception &e)
{
delete m_hostPacketizer;
m_hostPacketizer = NULL;
throw std::runtime_error(format_string("Error: Initial ping failure: %s", e.what()));
}
}
break;
}
case Peripheral::kHostPeripheralType_USB_HID:
{
UsbHidPeripheral *peripheral = NULL;
try
{
peripheral = new UsbHidPeripheral(config.usbHidVid, config.usbHidPid, config.usbHidSerialNumber.c_str(),
config.usbPath.c_str());
m_hostPacketizer = new UsbHidPacketizer(peripheral, config.packetTimeoutMs);
}
catch (...)
{
delete peripheral;
throw;
}
break;
}
#if defined(LINUX) && defined(__ARM__)
case Peripheral::kHostPeripheralType_I2C:
{
I2cPeripheral *peripheral =
new I2cPeripheral(config.comPortName.c_str(), config.i2cAddress, config.comPortSpeed);
m_hostPacketizer = new SerialPacketizer(peripheral, config.packetTimeoutMs);
if (config.ping)
{
// Send initial ping.
try
{
ping(0, 0, config.comPortSpeed, NULL);
}
catch (const std::exception &e)
{
throw std::runtime_error(format_string("Error: Initial ping failure: %s", e.what()));
}
}
break;
}
case Peripheral::kHostPeripheralType_SPI:
{
SpiPeripheral *peripheral = new SpiPeripheral(config.comPortName.c_str(), config.comPortSpeed,
config.spiPolarity, config.spiPhase, config.spiSequence);
m_hostPacketizer = new SerialPacketizer(peripheral, config.packetTimeoutMs);
if (config.ping)
{
// Send initial ping.
try
{
ping(0, 0, config.comPortSpeed, NULL);
}
catch (const std::exception &e)
{
throw std::runtime_error(format_string("Error: Initial ping failure: %s", e.what()));
}
}
break;
}
#endif // #if defined(LINUX) && defined(__ARM__)
case Peripheral::kHostPeripheralType_BUSPAL_UART:
{
BusPalUartPeripheral *peripheral =
new BusPalUartPeripheral(config.comPortName.c_str(), config.comPortSpeed, config.busPalConfig);
m_hostPacketizer = new SerialPacketizer(peripheral, config.packetTimeoutMs);
// Send initial ping.
// Bus pal peripheral interface will take care of the delays for us.
if (config.ping)
{
uint32_t buspalReadRetries;
#if defined(DEBUG)
buspalReadRetries = 0;
#else
buspalReadRetries = kBuspalReadRetries;
#endif
try
{
ping(buspalReadRetries, 0, 0, NULL);
}
catch (const std::exception &e)
{
throw std::runtime_error(format_string("Error: Initial ping failure: %s", e.what()));
}
}
break;
}
#if defined(LPCUSBSIO)
case Peripheral::kHostPeripheralType_LPCUSBSIO:
{
LpcUsbSioPeripheral *peripheral = new LpcUsbSioPeripheral(config.lpcUsbSioConfig);
m_hostPacketizer = new SerialPacketizer(peripheral, config.packetTimeoutMs);
if (config.ping)
{
// Send initial ping.
try
{
ping(0, 0, 0, NULL);
}
catch (const std::exception &e)
{
delete m_hostPacketizer;
m_hostPacketizer = NULL;
throw std::runtime_error(format_string("Error: Initial ping failure: %s", e.what()));
}
}
break;
}
#endif // #if defined(LPCUSBSIO)
default:
throw std::runtime_error(format_string("Error: Unsupported peripheral type(%d).", config.peripheralType));
}
}
// See host_bootloader.h for documentation of this method.
Bootloader::~Bootloader()
{
flush();
// Delete packetizer should close handles and free memory on Peripheral.
if (m_hostPacketizer)
{
delete m_hostPacketizer;
m_hostPacketizer = NULL;
}
}
// See host_bootloader.h for documentation of this method.
void Bootloader::flush()
{
// Finalize the packet interface.
if (m_hostPacketizer)
{
m_hostPacketizer->finalize();
}
}
// See host_bootloader.h for documentation of this method.
void Bootloader::execute(uint32_t entry_point, uint32_t param, uint32_t stack_pointer)
{
// Inject the execute(start_address, param, stack_pointer) command.
Execute cmd(entry_point, param, stack_pointer);
Log::info("Inject command '%s'\n", cmd.getName().c_str());
this->inject(cmd);
uint32_t fw_status = cmd.getResponseValues()->at(0);
std::string fw_msg = cmd.getStatusMessage(fw_status);
// Check the command status
if (fw_status != kStatus_Success)
{
throw std::runtime_error(fw_msg);
}
}
// See host_bootloader.h for documentation of this method.
void Bootloader::reset()
{
// Inject the reset command.
Reset cmd;
Log::info("Inject command '%s'\n", cmd.getName().c_str());
this->inject(cmd);
uint32_t fw_status = cmd.getResponseValues()->at(0);
std::string fw_msg = cmd.getStatusMessage(fw_status);
// Check the command status
if (fw_status != kStatus_Success)
{
throw std::runtime_error(fw_msg);
}
}
uint32_vector_t Bootloader::getProperty(property_t tag, uint32_t memoryIdorIndex)
{
// Inject the get-property(tag) command.
GetProperty cmd(tag, memoryIdorIndex);
Log::info("inject command '%s'\n", cmd.getName().c_str());
inject(cmd);
uint32_t fw_status = cmd.getResponseValues()->at(0);
std::string fw_msg = cmd.getStatusMessage(fw_status);
// Check the command status
if (fw_status != kStatus_Success)
{
throw std::runtime_error(fw_msg);
}
return *cmd.getResponseValues();
}
// See Updater.h for documentation of this method.
bool Bootloader::isCommandSupported(const cmd_t &command)
{
uint32_t fw_response = getProperty(kProperty_AvailableCommands, 0).at(1);
// See if the command is supported.
return ((fw_response & command.mask) == command.mask);
}
// See host_bootloader.h for documentation of this method.
standard_version_t Bootloader::getVersion()
{
return standard_version_t(getProperty(kProperty_CurrentVersion, 0).at(1));
}
// See host_bootloader.h for documentation of this method.
uint32_t Bootloader::getSecurityState()
{
// Inject the get-property command.
GetProperty cmd(kProperty_FlashSecurityState);
Log::info("inject command '%s'\n", cmd.getName().c_str());
this->inject(cmd);
uint32_t fw_status = cmd.getResponseValues()->at(0);
std::string fw_msg = cmd.getStatusMessage(fw_status);
// Check the command status
if (fw_status != kStatus_Success)
{
throw std::runtime_error(fw_msg);
}
return getProperty(kProperty_FlashSecurityState, 0).at(1);
}
// See host_bootloader.h for documentation of this method.
uint32_t Bootloader::getDataPacketSize()
{
return getProperty(kProperty_MaxPacketSize, 0).at(1);
}
// See host_bootloader.h for documentation of this method.
void Bootloader::ping(int retries, unsigned int delay, int comSpeed, int *actualComSpeed)
{
this->flush();
SerialPacketizer *pPacketizer = dynamic_cast<SerialPacketizer *>(m_hostPacketizer);
if (pPacketizer)
{
status_t status = pPacketizer->ping(retries, delay, NULL, comSpeed, actualComSpeed);
if (status != kStatus_Success)
{
this->flush();
Reset cmd; // dummy command to get access to status text.
// report ping failure in JSON output mode.
Json::Value root;
root["command"] = "ping";
root["status"] = Json::Value(Json::objectValue);
root["status"]["value"] = static_cast<Json::UInt>(status);
root["status"]["description"] =
format_string("%d (0x%X) %s", status, status, cmd.getStatusMessage(status).c_str());
root["response"] = Json::Value(Json::arrayValue);
Json::StyledWriter writer;
Log::json(writer.write(root).c_str());
throw std::runtime_error(cmd.getStatusMessage(status));
}
}
}
////////////////////////////////////////////////////////////////////////////////
// EOF
////////////////////////////////////////////////////////////////////////////////

1353
src/blfwk/src/BusPal.cpp Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,239 @@
/*
* Copyright (c) 2013-2014 Freescale Semiconductor, Inc.
* Copyright 2015-2020 NXP.
* All rights reserved.
*
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include "blfwk/BusPalPeripheral.h"
#include "blfwk/Logging.h"
#include "blfwk/format_string.h"
using namespace blfwk;
using namespace std;
////////////////////////////////////////////////////////////////////////////////
// Variables
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
// Code
////////////////////////////////////////////////////////////////////////////////
// See BusPalUartPeripheral.h for documentation of this method.
BusPalUartPeripheral::BusPalUartPeripheral(const char *port, long speed, const BusPal::BusPalConfigData &config)
: UartPeripheral(port, speed)
{
m_busPal = new BusPal(m_fileDescriptor);
if (m_busPal->enterBitBangMode())
{
configure(config);
}
else
{
delete m_busPal;
m_busPal = NULL;
throw std::runtime_error(format_string("Error: BusPalUartPeripheral() cannot enter BitBang Mode."));
}
}
// See BusPalUartPeripheral.h for documentation of this method.
BusPalUartPeripheral::~BusPalUartPeripheral()
{
if (m_busPal)
{
free(m_busPal);
}
}
// See BusPalUartPeripheral.h for documentation of this method.
void BusPalUartPeripheral::configure(const BusPal::BusPalConfigData &config)
{
switch (config.function)
{
case BusPal::kBusPalFunction_SPI:
if (!m_busPal->enterSpiMode())
{
throw std::runtime_error(format_string("Error: BusPalUartPeripheral() cannot enter SPI Mode."));
}
if (!m_busPal->setSpiSpeed(config.spiSpeedKHz))
{
throw std::runtime_error(
format_string("Error: BusPalUartPeripheral() cannot set SPI speed(%d kHz).", config.spiSpeedKHz));
}
if (!m_busPal->setSpiConfig(config.spiPolarity, config.spiPhase, config.spiDirection))
{
throw std::runtime_error(format_string(
"Error: BusPalUartPeripheral() cannot set SPI polarity(%s(%d)), phase(%s(%d)), and "
"direction(%s(%d)).",
config.spiPolarity == BusPal::kSpiClockPolarity_ActiveHigh ? "ActiveHigh" : "ActiveLow",
config.spiPolarity,
config.spiPhase == BusPal::kSpiClockPhase_FirstEdge ? "FirstEdge" : "SecondEdge", config.spiPhase,
config.spiDirection == BusPal::kSpiLsbFirst ? "LsbFirst" : "MsbFirst", config.spiDirection));
}
break;
case BusPal::kBusPalFunction_CAN:
if (!m_busPal->enterCanMode())
{
throw std::runtime_error(format_string("Error: BusPalUartPeripheral() cannot enter CAN Mode."));
}
if (!m_busPal->setCanSpeed(config.canSpeed))
{
throw std::runtime_error(
format_string("Error: BusPalUartPeripheral() cannot set CAN speed(%d).", config.canSpeed));
}
if (!m_busPal->setCanTxid(config.canTxid))
{
throw std::runtime_error(
format_string("Error: BusPalUartPeripheral() cannot set CAN txid(0x%x).", config.canTxid));
}
if (!m_busPal->setCanRxid(config.canRxid))
{
throw std::runtime_error(
format_string("Error: BusPalUartPeripheral() cannot set CAN rxid(0x%x).", config.canTxid));
}
break;
case BusPal::kBusPalFunction_I2C:
if (!m_busPal->enterI2cMode())
{
throw std::runtime_error(format_string("Error: BusPalUartPeripheral() cannot enter I2C Mode."));
}
if (!m_busPal->setI2cAddress(config.i2cAddress))
{
throw std::runtime_error(
format_string("Error: BusPalUartPeripheral() cannot set I2C address %02X.", config.i2cAddress));
}
if (!m_busPal->setI2cSpeed(config.i2cSpeedKHz))
{
throw std::runtime_error(
format_string("Error: BusPalUartPeripheral() cannot set I2C speed(%d KHz).", config.i2cSpeedKHz));
}
break;
case BusPal::kBusPalFunction_SAI:
if (!m_busPal->enterSaiMode())
{
throw std::runtime_error(format_string("Error: BusPalUartPeripheral() cannot enter SAI Mode."));
}
if (!m_busPal->setSaiSpeed(config.saiSpeedHz))
{
throw std::runtime_error(
format_string("Error: BusPalUartPeripheral() cannot set SAI speed(%d Hz).", config.saiSpeedHz));
}
break;
case BusPal::kBusPalFunction_GPIO_CONFIG:
if (!m_busPal->enterBitBangMode())
{
throw std::runtime_error(
format_string("Error: BusPalUartPeripheral() cannot enter Bitbang mode for GPIO setting."));
}
if (!m_busPal->rawConfigurePins(config.gpioPort, config.gpioPinNum, config.gpioMux))
{
throw std::runtime_error(
format_string("Error: BusPalUartPeripheral() cannot configure GPIO %c,%02X,%02X", config.gpioPort,
config.gpioPinNum, config.gpioMux));
}
break;
case BusPal::kBusPalFunction_GPIO_SET:
if (!m_busPal->enterBitBangMode())
{
throw std::runtime_error(
format_string("Error: BusPalUartPeripheral() cannot enter Bitbang mode for GPIO setting."));
}
if (!m_busPal->rawSetPins(config.gpioPort, config.gpioPinNum, config.gpioLevel))
{
throw std::runtime_error(format_string("Error: BusPalUartPeripheral() cannot set GPIO %c,%02X,%02X",
config.gpioPort, config.gpioPinNum, config.gpioLevel));
}
break;
case BusPal::kBusPalFunction_FPGA_CLOCK_SET:
if (!m_busPal->enterBitBangMode())
{
throw std::runtime_error(
format_string("Error: BusPalUartPeripheral() cannot enter Bitbang mode for FPGA clock setting."));
}
if (!m_busPal->setFPGAClock(config.fpgaClockMhz))
{
throw std::runtime_error(format_string("Error: BusPalUartPeripheral() cannot set FPGA clock to %2d MHz",
config.fpgaClockMhz));
}
break;
default:
throw std::runtime_error("Unsupported BusPal function type");
}
}
// See BusPalUartPeripheral.h for documentation of this method.
status_t BusPalUartPeripheral::read(uint8_t *buffer, uint32_t requestedBytes, uint32_t *actualBytes, uint32_t timeoutMs)
{
assert(buffer);
// Read the requested number of bytes.
int count = m_busPal->read(buffer, requestedBytes);
if (actualBytes)
{
*actualBytes = count;
}
if (count < (int)requestedBytes)
{
// Anything less than requestedBytes is a timeout error.
Log::error("Error: Bus Pal read returned 0\n");
return kStatus_Timeout;
}
return kStatus_Success;
}
// See BusPalUartPeripheral.h for documentation of this method.
status_t BusPalUartPeripheral::write(const uint8_t *buffer, uint32_t byteCount)
{
assert(buffer);
const int maxBulk = BusPal::kBulkTransferMax;
int numBulk = (byteCount / maxBulk);
int remaining = byteCount - (numBulk * maxBulk);
bool rc = true;
// Send buffer in max bulk transfer size chunks.
for (int i = 0; i < numBulk; ++i)
{
rc = m_busPal->write(&buffer[i * maxBulk], maxBulk);
if (!rc)
{
return kStatus_Fail;
}
}
// Send the last OR partial chunk.
if (rc && remaining)
{
rc = m_busPal->write(&buffer[numBulk * maxBulk], remaining);
if (!rc)
{
return kStatus_Fail;
}
}
return kStatus_Success;
}
////////////////////////////////////////////////////////////////////////////////
// EOF
////////////////////////////////////////////////////////////////////////////////

4495
src/blfwk/src/Command.cpp Normal file

File diff suppressed because it is too large Load Diff

44
src/blfwk/src/Crc.cpp Normal file
View File

@ -0,0 +1,44 @@
/*
* Copyright (c) 2013-2015 Freescale Semiconductor, Inc.
* All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include "blfwk/Crc.h"
#include "property/property.h"
#include "crc/crc32.h"
using namespace blfwk;
// See Crc.h for documentation of this method.
uint32_t Crc::calculate_application_crc32(const uint8_t *start, uint32_t length)
{
uint32_t crc32;
// Initialize the CRC32 information
crc32_data_t crcInfo;
crc32_init(&crcInfo);
// Run CRC, Considering skip crcExpectedValue address
const bootloader_configuration_data_t *config =
NULL; // Just used for calculate the offset, must not change the region it points to.
uint32_t bypassStartAddress = 0x3C0 + ((uint32_t)&config->crcExpectedValue - (uint32_t)&config->tag);
uint32_t bypassEndAddress = bypassStartAddress + sizeof(config->crcExpectedValue);
if (length <= bypassStartAddress)
{
crc32_update(&crcInfo, (uint8_t *)start, length);
}
else
{
// Assume that crcExpectedValue address (4 byte) resides in crc addresses completely
crc32_update(&crcInfo, (uint8_t *)start, bypassStartAddress);
crc32_update(&crcInfo, (uint8_t *)(start + bypassEndAddress), length - bypassEndAddress);
}
// Finalize the CRC calculations
crc32_finalize(&crcInfo, &crc32);
return crc32;
}

View File

@ -0,0 +1,258 @@
/*
* Copyright (c) 2013-2014 Freescale Semiconductor, Inc.
* All rights reserved.
*
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <algorithm>
#include <assert.h>
#include <string.h>
#include "blfwk/DataSource.h"
#include "blfwk/DataTarget.h"
using namespace blfwk;
#pragma warning(disable : 4068) /* disable unknown pragma warnings */
#pragma mark *** DataSource::PatternSegment ***
DataSource::PatternSegment::PatternSegment(DataSource &source)
: DataSource::Segment(source)
, m_pattern()
{
}
DataSource::PatternSegment::PatternSegment(DataSource &source, const SizedIntegerValue &pattern)
: DataSource::Segment(source)
, m_pattern(pattern)
{
}
DataSource::PatternSegment::PatternSegment(DataSource &source, uint8_t pattern)
: DataSource::Segment(source)
, m_pattern(static_cast<uint8_t>(pattern))
{
}
DataSource::PatternSegment::PatternSegment(DataSource &source, uint16_t pattern)
: DataSource::Segment(source)
, m_pattern(static_cast<uint16_t>(pattern))
{
}
DataSource::PatternSegment::PatternSegment(DataSource &source, uint32_t pattern)
: DataSource::Segment(source)
, m_pattern(static_cast<uint32_t>(pattern))
{
}
unsigned DataSource::PatternSegment::getData(unsigned offset, unsigned maxBytes, uint8_t *buffer)
{
memset(buffer, 0, maxBytes);
return maxBytes;
}
//! The pattern segment's length is a function of the data target. If the
//! target is bounded, then the segment's length is simply the target's
//! length. Otherwise, if no target has been set or the target is unbounded,
//! then the length returned is 0.
unsigned DataSource::PatternSegment::getLength()
{
DataTarget *target = m_source.getTarget();
if (!target)
{
return 0;
}
uint32_t length;
if (target->isBounded())
{
length = target->getEndAddress() - target->getBeginAddress();
}
else
{
length = m_pattern.getSize();
}
return length;
}
#pragma mark *** PatternSource ***
PatternSource::PatternSource()
: DataSource()
, DataSource::PatternSegment((DataSource &)*this)
{
}
PatternSource::PatternSource(const SizedIntegerValue &value)
: DataSource()
, DataSource::PatternSegment((DataSource &)*this, value)
{
}
#pragma mark *** UnmappedDataSource ***
UnmappedDataSource::UnmappedDataSource()
: DataSource()
, DataSource::Segment((DataSource &)*this)
, m_data()
, m_length(0)
{
}
UnmappedDataSource::UnmappedDataSource(const uint8_t *data, unsigned length)
: DataSource()
, DataSource::Segment((DataSource &)*this)
, m_data()
, m_length(0)
{
setData(data, length);
}
//! Makes a copy of \a data that is freed when the data source is
//! destroyed. The caller does not have to maintain \a data after this call
//! returns.
void UnmappedDataSource::setData(const uint8_t *data, unsigned length)
{
m_data.safe_delete();
uint8_t *dataCopy = new uint8_t[length];
memcpy(dataCopy, data, length);
m_data = dataCopy;
m_length = length;
}
unsigned UnmappedDataSource::getData(unsigned offset, unsigned maxBytes, uint8_t *buffer)
{
assert(offset < m_length);
unsigned copyBytes = std::min<unsigned>(m_length - offset, maxBytes);
memcpy(buffer, &m_data[offset], copyBytes);
return copyBytes;
}
//! The unmapped datasource as segment's base address is a function of the data target.
//! If the target is not NULL, then the segment's base address is simply the target's
//! beginAddress. Otherwise, if no target has been set, then the base address returned is 0.
uint32_t UnmappedDataSource::getBaseAddress()
{
return getTarget() == NULL ? 0 : getTarget()->getBeginAddress();
}
#pragma mark *** MemoryImageDataSource ***
MemoryImageDataSource::MemoryImageDataSource(StExecutableImage *image)
: DataSource()
, m_image(image)
{
// reserve enough room for all segments
m_segments.reserve(m_image->getRegionCount());
}
MemoryImageDataSource::~MemoryImageDataSource()
{
segment_array_t::iterator it = m_segments.begin();
for (; it != m_segments.end(); ++it)
{
// delete this segment if it has been created
if (*it)
{
delete *it;
}
}
}
unsigned MemoryImageDataSource::getSegmentCount()
{
return m_image->getRegionCount();
}
DataSource::Segment *MemoryImageDataSource::getSegmentAt(unsigned index)
{
// return previously created segment
if (index < m_segments.size() && m_segments[index])
{
return m_segments[index];
}
// extend array out to this index
if (index >= m_segments.size() && index < m_image->getRegionCount())
{
m_segments.resize(index + 1, NULL);
}
// create the new segment object
DataSource::Segment *newSegment;
const StExecutableImage::MemoryRegion &region = m_image->getRegionAtIndex(index);
if (region.m_type == StExecutableImage::TEXT_REGION)
{
newSegment = new TextSegment(*this, m_image, index);
}
else if (region.m_type == StExecutableImage::FILL_REGION)
{
newSegment = new FillSegment(*this, m_image, index);
}
else
{
newSegment = NULL;
}
m_segments[index] = newSegment;
return newSegment;
}
#pragma mark *** MemoryImageDataSource::TextSegment ***
MemoryImageDataSource::TextSegment::TextSegment(MemoryImageDataSource &source, StExecutableImage *image, unsigned index)
: DataSource::Segment(source)
, m_image(image)
, m_index(index)
{
}
unsigned MemoryImageDataSource::TextSegment::getData(unsigned offset, unsigned maxBytes, uint8_t *buffer)
{
const StExecutableImage::MemoryRegion &region = m_image->getRegionAtIndex(m_index);
assert(region.m_type == StExecutableImage::TEXT_REGION);
unsigned copyBytes = std::min<unsigned>(region.m_length - offset, maxBytes);
memcpy(buffer, &region.m_data[offset], copyBytes);
return copyBytes;
}
unsigned MemoryImageDataSource::TextSegment::getLength()
{
const StExecutableImage::MemoryRegion &region = m_image->getRegionAtIndex(m_index);
return region.m_length;
}
uint32_t MemoryImageDataSource::TextSegment::getBaseAddress()
{
const StExecutableImage::MemoryRegion &region = m_image->getRegionAtIndex(m_index);
return region.m_address;
}
#pragma mark *** MemoryImageDataSource::FillSegment ***
MemoryImageDataSource::FillSegment::FillSegment(MemoryImageDataSource &source, StExecutableImage *image, unsigned index)
: DataSource::PatternSegment(source)
, m_image(image)
, m_index(index)
{
SizedIntegerValue zero(0, kWordSize);
setPattern(zero);
}
unsigned MemoryImageDataSource::FillSegment::getLength()
{
const StExecutableImage::MemoryRegion &region = m_image->getRegionAtIndex(m_index);
return region.m_length;
}
uint32_t MemoryImageDataSource::FillSegment::getBaseAddress()
{
const StExecutableImage::MemoryRegion &region = m_image->getRegionAtIndex(m_index);
return region.m_address;
}

View File

@ -0,0 +1,142 @@
/*
* File: DataSourceImager.cpp
*
* Copyright (c) Freescale Semiconductor, Inc. All rights reserved.
* See included license file for license details.
*/
#include "blfwk/DataSourceImager.h"
#include <stdlib.h>
#include <string.h>
using namespace blfwk;
DataSourceImager::DataSourceImager()
: Blob()
, m_fill(0)
, m_baseAddress(0)
, m_isBaseAddressSet(false)
{
}
void DataSourceImager::setBaseAddress(uint32_t address)
{
m_baseAddress = address;
m_isBaseAddressSet = true;
}
void DataSourceImager::setFillPattern(uint8_t pattern)
{
m_fill = pattern;
}
void DataSourceImager::reset()
{
clear();
m_fill = 0;
m_baseAddress = 0;
m_isBaseAddressSet = false;
}
//! \param dataSource Pointer to an instance of a concrete data source subclass.
//!
void DataSourceImager::addDataSource(DataSource *source)
{
unsigned segmentCount = source->getSegmentCount();
unsigned index = 0;
for (; index < segmentCount; ++index)
{
addDataSegment(source->getSegmentAt(index));
}
}
//! \param segment The segment to add. May be any type of data segment, including
//! a pattern segment.
void DataSourceImager::addDataSegment(DataSource::Segment *segment)
{
DataSource::PatternSegment *patternSegment = dynamic_cast<DataSource::PatternSegment *>(segment);
unsigned segmentLength = segment->getLength();
bool segmentHasLocation = segment->hasNaturalLocation();
uint32_t segmentAddress = segment->getBaseAddress();
uint8_t *toPtr = NULL;
unsigned addressDelta;
unsigned newLength;
// If a pattern segment's length is 0 then make it as big as the fill pattern.
// This needs to be done before the buffer is adjusted.
if (patternSegment && segmentLength == 0)
{
SizedIntegerValue &pattern = patternSegment->getPattern();
segmentLength = pattern.getSize();
}
if (segmentLength)
{
if (segmentHasLocation)
{
// Make sure a base address is set.
if (!m_isBaseAddressSet)
{
m_baseAddress = segmentAddress;
m_isBaseAddressSet = true;
}
// The segment is located before our buffer's first address.
// toPtr is not set in this if, but in the else branch of the next if.
// Unless the segment completely overwrite the current data.
if (segmentAddress < m_baseAddress)
{
addressDelta = m_baseAddress - segmentAddress;
uint8_t *newData = (uint8_t *)malloc(m_length + addressDelta);
memcpy(&newData[addressDelta], m_data, m_length);
free(m_data);
m_data = newData;
m_length += addressDelta;
m_baseAddress = segmentAddress;
}
// This segment is located or extends outside of our buffer.
if (segmentAddress + segmentLength > m_baseAddress + m_length)
{
newLength = segmentAddress + segmentLength - m_baseAddress;
m_data = (uint8_t *)realloc(m_data, newLength);
// Clear any bytes between the old data and the new segment.
addressDelta = segmentAddress - (m_baseAddress + m_length);
if (addressDelta)
{
memset(m_data + m_length, 0, addressDelta);
}
toPtr = m_data + (segmentAddress - m_baseAddress);
m_length = newLength;
}
else
{
toPtr = m_data + (segmentAddress - m_baseAddress);
}
}
// Segment has no natural location, so just append it to the end of our buffer.
else
{
newLength = m_length + segmentLength;
m_data = (uint8_t *)realloc(m_data, newLength);
toPtr = m_data + m_length;
m_length = newLength;
}
}
// A loop is used because getData() may fill in less than the requested
// number of bytes per call.
unsigned offset = 0;
while (offset < segmentLength)
{
offset += segment->getData(offset, segmentLength - offset, toPtr + offset);
}
}

View File

@ -0,0 +1,60 @@
/*
* Copyright (c) 2013-2014 Freescale Semiconductor, Inc.
* All rights reserved.
*
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include "blfwk/DataTarget.h"
#include "blfwk/DataSource.h"
#include "blfwk/BlfwkErrors.h"
#include <algorithm>
using namespace blfwk;
//! \exception blfwk::semantic_error Thrown if the source has multiple segments.
DataTarget::AddressRange ConstantDataTarget::getRangeForSegment(DataSource &source, DataSource::Segment &segment)
{
// can't handle multi-segment data sources
if (source.getSegmentCount() > 1)
{
throw semantic_error("constant targets only support single-segment sources");
}
// always relocate the segment to our begin address
AddressRange range;
range.m_begin = m_begin;
if (isBounded())
{
// we have an end address. trim the result range to the segment size
// or let the end address crop the segment.
range.m_end = std::min<uint32_t>(m_end, m_begin + segment.getLength());
}
else
{
// we have no end address, so the segment size determines it.
range.m_end = m_begin + segment.getLength();
}
return range;
}
//! If the \a segment has a natural location, the returned address range extends
//! from the segment's base address to its base address plus its length.
//!
//! \exception blfwk::semantic_error This exception is thrown if the \a segment
//! does not have a natural location associated with it.
DataTarget::AddressRange NaturalDataTarget::getRangeForSegment(DataSource &source, DataSource::Segment &segment)
{
if (!segment.hasNaturalLocation())
{
throw semantic_error("source has no natural location");
}
AddressRange range;
range.m_begin = segment.getBaseAddress();
range.m_end = segment.getBaseAddress() + segment.getLength();
return range;
}

View File

@ -0,0 +1,627 @@
/*
* Copyright (c) 2013-2014 Freescale Semiconductor, Inc.
* Copyright 2015-2020 NXP
* All rights reserved.
*
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <ctype.h>
#include <algorithm>
#include "blfwk/ELFSourceFile.h"
#include "blfwk/GHSSecInfo.h"
#include "blfwk/Logging.h"
#ifdef LINUX
#include <string.h>
#endif
//! The name of the toolset option.
#define kToolsetOptionName "toolset"
#define kGHSToolsetName "GHS"
#define kGCCToolsetName "GCC"
#define kGNUToolsetName "GNU"
#define kADSToolsetName "ADS"
//! Name of the option to control .secinfo action.
#define kSecinfoClearOptionName "secinfoClear"
#define kSecinfoDefaultName "DEFAULT"
#define kSecinfoIgnoreName "IGNORE"
#define kSecinfoROMName "ROM"
#define kSecinfoCName "C"
using namespace blfwk;
ELFSourceFile::ELFSourceFile(const std::string &path)
: SourceFile(path, kELFSourceFile)
, m_toolset(kUnknownToolset)
, m_secinfoOption(kSecinfoDefault)
{
}
ELFSourceFile::~ELFSourceFile() {}
bool ELFSourceFile::isELFFile(std::istream &stream)
{
try
{
StELFFile elf(stream);
return true;
}
catch (...)
{
return false;
}
}
void ELFSourceFile::open()
{
// Read toolset option
m_toolset = readToolsetOption();
// Read option and select default value
m_secinfoOption = readSecinfoClearOption();
if (m_secinfoOption == kSecinfoDefault)
{
m_secinfoOption = kSecinfoCStartupClear;
}
// Open the stream
SourceFile::open();
m_file = new StELFFile(*m_stream);
// m_file->dumpSections();
// Set toolset in elf file object
switch (m_toolset)
{
// default toolset is GHS
case kGHSToolset:
case kUnknownToolset:
m_file->setELFVariant(eGHSVariant);
break;
case kGCCToolset:
m_file->setELFVariant(eGCCVariant);
break;
case kADSToolset:
m_file->setELFVariant(eARMVariant);
break;
}
}
void ELFSourceFile::close()
{
SourceFile::close();
m_file.safe_delete();
}
elf_toolset_t ELFSourceFile::readToolsetOption()
{
do
{
const OptionContext *options = getOptions();
if (!options || !options->hasOption(kToolsetOptionName))
{
break;
}
const Value *value = options->getOption(kToolsetOptionName);
const StringValue *stringValue = dynamic_cast<const StringValue *>(value);
if (!stringValue)
{
// Not a string value, warn the user.
Log::log(Logger::kWarning, "invalid type for 'toolset' option\n");
break;
}
std::string toolsetName = *stringValue;
// convert option value to uppercase
std::transform<std::string::const_iterator, std::string::iterator, int (*)(int)>(
toolsetName.begin(), toolsetName.end(), toolsetName.begin(), toupper);
if (toolsetName == kGHSToolsetName)
{
return kGHSToolset;
}
else if (toolsetName == kGCCToolsetName || toolsetName == kGNUToolsetName)
{
return kGCCToolset;
}
else if (toolsetName == kADSToolsetName)
{
return kADSToolset;
}
// Unrecognized option value, log a warning.
Log::log(Logger::kWarning, "unrecognized value for 'toolset' option\n");
} while (0);
return kUnknownToolset;
}
//! It is up to the caller to convert from kSecinfoDefault to the actual default
//! value.
secinfo_clear_t ELFSourceFile::readSecinfoClearOption()
{
do
{
const OptionContext *options = getOptions();
if (!options || !options->hasOption(kSecinfoClearOptionName))
{
break;
}
const Value *value = options->getOption(kSecinfoClearOptionName);
const StringValue *stringValue = dynamic_cast<const StringValue *>(value);
if (!stringValue)
{
// Not a string value, warn the user.
Log::log(Logger::kWarning, "invalid type for 'secinfoClear' option\n");
break;
}
std::string secinfoOption = *stringValue;
// convert option value to uppercase
std::transform<std::string::const_iterator, std::string::iterator, int (*)(int)>(
secinfoOption.begin(), secinfoOption.end(), secinfoOption.begin(), toupper);
if (secinfoOption == kSecinfoDefaultName)
{
return kSecinfoDefault;
}
else if (secinfoOption == kSecinfoIgnoreName)
{
return kSecinfoIgnore;
}
else if (secinfoOption == kSecinfoROMName)
{
return kSecinfoROMClear;
}
else if (secinfoOption == kSecinfoCName)
{
return kSecinfoCStartupClear;
}
// Unrecognized option value, log a warning.
Log::log(Logger::kWarning, "unrecognized value for 'secinfoClear' option\n");
} while (0);
return kSecinfoDefault;
}
//! To create a data source for all sections of the ELF file, a WildcardMatcher
//! is instantiated and passed to createDataSource(StringMatcher&).
DataSource *ELFSourceFile::createDataSource()
{
WildcardMatcher matcher;
return createDataSource(matcher);
}
DataSource *ELFSourceFile::createDataSource(const std::vector<uint32_t> &baseAddresses, bool match)
{
assert(m_file);
ELFDataSource *source = new ELFDataSource(m_file);
source->setSecinfoOption(m_secinfoOption);
if (match)
{
Log::log(Logger::kDebug2, "filtering sections of file that match base addresses: 0x%08X\n", baseAddresses[0]);
for (unsigned i = 1; i < baseAddresses.size(); i++)
{
Log::log(Logger::kDebug2, " 0x%08X\n",
baseAddresses[i]);
}
}
else
{
Log::log(Logger::kDebug2, "filtering sections of file that exclude base addresses: 0x%08X\n", baseAddresses[0]);
for (unsigned i = 1; i < baseAddresses.size(); i++)
{
Log::log(Logger::kDebug2, " 0x%08X\n",
baseAddresses[i]);
}
}
try
{
// We start at section 1 to skip the null section that is always first.
unsigned index = 1;
for (; index < m_file->getSectionCount(); ++index)
{
const Elf32_Shdr &header = m_file->getSectionAtIndex(index);
std::string name = m_file->getSectionNameAtIndex(header.sh_name);
// Ignore most section types
if (!(header.sh_type == SHT_PROGBITS || header.sh_type == SHT_NOBITS))
{
continue;
}
// Ignore sections that don't have the allocate flag set.
if ((header.sh_flags & SHF_ALLOC) == 0)
{
continue;
}
bool contains =
std::find(baseAddresses.begin(), baseAddresses.end(), header.sh_addr) != baseAddresses.end();
// If we are not matching the supplied address then we will add any section that does not have the
// baseAddress If we are matching we will only include the section that matches the baseAddress
if ((!match && !contains) || (match && contains))
{
Log::log(Logger::kDebug2, "creating segment for section %s with base address = 0x%08X\n", name.c_str(),
header.sh_addr);
source->addSection(index);
}
else
{
Log::log(Logger::kDebug2, "section %s with base address of 0x%08X is excluded\n", name.c_str(),
header.sh_addr);
}
}
}
catch (...)
{
delete source;
throw;
}
Log::log(Logger::kDebug2, "\n");
return source;
}
DataSource *ELFSourceFile::createDataSource(StringMatcher &matcher)
{
assert(m_file);
ELFDataSource *source = new ELFDataSource(m_file);
source->setSecinfoOption(m_secinfoOption);
Log::log(Logger::kDebug2, "filtering sections of file: %s\n", getPath().c_str());
try
{
// We start at section 1 to skip the null section that is always first.
unsigned index = 1;
for (; index < m_file->getSectionCount(); ++index)
{
const Elf32_Shdr &header = m_file->getSectionAtIndex(index);
std::string name = m_file->getSectionNameAtIndex(header.sh_name);
// Ignore most section types
if (!(header.sh_type == SHT_PROGBITS || header.sh_type == SHT_NOBITS))
{
continue;
}
// Ignore sections that don't have the allocate flag set.
if ((header.sh_flags & SHF_ALLOC) == 0)
{
continue;
}
if (matcher.match(name))
{
Log::log(Logger::kDebug2, "creating segment for section %s\n", name.c_str());
source->addSection(index);
}
else
{
Log::log(Logger::kDebug2, "section %s did not match\n", name.c_str());
}
}
}
catch (...)
{
delete source;
throw;
}
return source;
}
//! It is assumed that all ELF files have an entry point.
//!
bool ELFSourceFile::hasEntryPoint()
{
return true;
}
//! The StELFFile::getTypeOfSymbolAtIndex() method uses different methods of determining
//! ARM/Thumb mode depending on the toolset.
uint32_t ELFSourceFile::getEntryPointAddress()
{
uint32_t entryPoint = 0;
// get entry point address
const Elf32_Ehdr &header = m_file->getFileHeader();
// find symbol corresponding to entry point and determine if
// it is arm or thumb mode
unsigned symbolIndex = m_file->getIndexOfSymbolAtAddress(header.e_entry);
if (symbolIndex != 0)
{
ARMSymbolType_t symbolType = m_file->getTypeOfSymbolAtIndex(symbolIndex);
bool entryPointIsThumb = (symbolType == eThumbSymbol);
const Elf32_Sym &symbol = m_file->getSymbolAtIndex(symbolIndex);
std::string symbolName = m_file->getSymbolName(symbol);
Log::log(Logger::kDebug2, "Entry point is %s@0x%08x (%s)\n", symbolName.c_str(), symbol.st_value,
entryPointIsThumb ? "Thumb" : "ARM");
// set entry point, setting the low bit if it is thumb mode
entryPoint = header.e_entry + (entryPointIsThumb ? 1 : 0);
}
else
{
entryPoint = header.e_entry;
}
return entryPoint;
}
//! \return A DataTarget that describes the named section.
//! \retval NULL There was no section with the requested name.
DataTarget *ELFSourceFile::createDataTargetForSection(const std::string &section)
{
assert(m_file);
unsigned index = m_file->getIndexOfSectionWithName(section);
if (index == SHN_UNDEF)
{
return NULL;
}
const Elf32_Shdr &sectionHeader = m_file->getSectionAtIndex(index);
uint32_t beginAddress = sectionHeader.sh_addr;
uint32_t endAddress = beginAddress + sectionHeader.sh_size;
ConstantDataTarget *target = new ConstantDataTarget(beginAddress, endAddress);
return target;
}
//! \return A DataTarget instance pointing at the requested symbol.
//! \retval NULL No symbol matching the requested name was found.
DataTarget *ELFSourceFile::createDataTargetForSymbol(const std::string &symbol)
{
assert(m_file);
unsigned symbolCount = m_file->getSymbolCount();
unsigned i;
for (i = 0; i < symbolCount; ++i)
{
const Elf32_Sym &symbolHeader = m_file->getSymbolAtIndex(i);
std::string symbolName = m_file->getSymbolName(symbolHeader);
if (symbolName == symbol)
{
ARMSymbolType_t symbolType = m_file->getTypeOfSymbolAtIndex(i);
bool symbolIsThumb = (symbolType == eThumbSymbol);
uint32_t beginAddress = symbolHeader.st_value + (symbolIsThumb ? 1 : 0);
uint32_t endAddress = beginAddress + symbolHeader.st_size;
ConstantDataTarget *target = new ConstantDataTarget(beginAddress, endAddress);
return target;
}
}
// didn't find a matching symbol
return NULL;
}
bool ELFSourceFile::hasSymbol(const std::string &name)
{
Elf32_Sym symbol;
return lookupSymbol(name, symbol);
}
uint32_t ELFSourceFile::getSymbolValue(const std::string &name)
{
unsigned symbolCount = m_file->getSymbolCount();
unsigned i;
for (i = 0; i < symbolCount; ++i)
{
const Elf32_Sym &symbolHeader = m_file->getSymbolAtIndex(i);
std::string symbolName = m_file->getSymbolName(symbolHeader);
if (symbolName == name)
{
// If the symbol is a function, then we check to see if it is Thumb code and set bit 0 if so.
if (ELF32_ST_TYPE(symbolHeader.st_info) == STT_FUNC)
{
ARMSymbolType_t symbolType = m_file->getTypeOfSymbolAtIndex(i);
bool symbolIsThumb = (symbolType == eThumbSymbol);
return symbolHeader.st_value + (symbolIsThumb ? 1 : 0);
}
else
{
return symbolHeader.st_value;
}
}
}
// Couldn't find the symbol, so return 0.
return 0;
}
unsigned ELFSourceFile::getSymbolSize(const std::string &name)
{
Elf32_Sym symbol;
if (!lookupSymbol(name, symbol))
{
return 0;
}
return symbol.st_size;
}
//! \param name The name of the symbol on which info is wanted.
//! \param[out] info Upon succssful return this is filled in with the symbol's information.
//!
//! \retval true The symbol was found and \a info is valid.
//! \retval false No symbol with \a name was found in the file.
bool ELFSourceFile::lookupSymbol(const std::string &name, Elf32_Sym &info)
{
assert(m_file);
unsigned symbolCount = m_file->getSymbolCount();
unsigned i;
for (i = 0; i < symbolCount; ++i)
{
const Elf32_Sym &symbol = m_file->getSymbolAtIndex(i);
std::string thisSymbolName = m_file->getSymbolName(symbol);
// Is this the symbol we're looking for?
if (thisSymbolName == name)
{
info = symbol;
return true;
}
}
// Didn't file the symbol.
return false;
}
ELFSourceFile::ELFDataSource::~ELFDataSource()
{
segment_vector_t::iterator it = m_segments.begin();
for (; it != m_segments.end(); ++it)
{
delete *it;
}
}
//! Not all sections will actually result in a new segment being created. Only
//! those sections whose type is #SHT_PROGBITS or #SHT_NOBITS will create
//! a new segment. Also, only sections whose size is non-zero will actually
//! create a segment.
//!
//! In addition to this, ELF files that have been marked as being created by
//! the Green Hills Software toolset have an extra step. #SHT_NOBITS sections
//! are looked up in the .secinfo section to determine if they really
//! should be filled. If not in the .secinfo table, no segment will be
//! created for the section.
void ELFSourceFile::ELFDataSource::addSection(unsigned sectionIndex)
{
// get section info
const Elf32_Shdr &section = m_elf->getSectionAtIndex(sectionIndex);
if (section.sh_size == 0)
{
// empty section, so ignore it
return;
}
// create the right segment subclass based on the section type
DataSource::Segment *segment = NULL;
if (section.sh_type == SHT_PROGBITS)
{
segment = new ProgBitsSegment(*this, m_elf, sectionIndex);
}
else if (section.sh_type == SHT_NOBITS)
{
// Always add NOBITS sections by default.
bool addNobits = true;
// For GHS ELF files, we use the secinfoClear option to figure out what to do.
// If set to ignore, treat like a normal ELF file and always add. If set to
// ROM, then only clear if the section is listed in .secinfo. Otherwise if set
// to C startup, then let the C startup do all clearing.
if (m_elf->ELFVariant() == eGHSVariant)
{
GHSSecInfo secinfo(m_elf);
// If there isn't a .secinfo section present then use the normal ELF rules
// and always add NOBITS sections.
if (secinfo.hasSecinfo() && m_secinfoOption != kSecinfoIgnore)
{
switch (m_secinfoOption)
{
case kSecinfoROMClear:
addNobits = secinfo.isSectionFilled(section);
break;
case kSecinfoCStartupClear:
addNobits = false;
break;
default:
// Do nothing.
break;
}
}
}
if (addNobits)
{
segment = new NoBitsSegment(*this, m_elf, sectionIndex);
}
else
{
std::string name = m_elf->getSectionNameAtIndex(section.sh_name);
Log::log(Logger::kDebug2, "..section %s is not filled\n", name.c_str());
}
}
// add segment if one was created
if (segment)
{
m_segments.push_back(segment);
}
}
ELFSourceFile::ELFDataSource::ProgBitsSegment::ProgBitsSegment(ELFDataSource &source, StELFFile *elf, unsigned index)
: DataSource::Segment(source)
, m_elf(elf)
, m_sectionIndex(index)
{
}
unsigned ELFSourceFile::ELFDataSource::ProgBitsSegment::getData(unsigned offset, unsigned maxBytes, uint8_t *buffer)
{
const Elf32_Shdr &section = m_elf->getSectionAtIndex(m_sectionIndex);
uint8_t *data = m_elf->getSectionDataAtIndex(m_sectionIndex);
assert(offset < section.sh_size);
unsigned copyBytes = std::min<unsigned>(section.sh_size - offset, maxBytes);
if (copyBytes)
{
memcpy(buffer, &data[offset], copyBytes);
}
delete[] data;
return copyBytes;
}
unsigned ELFSourceFile::ELFDataSource::ProgBitsSegment::getLength()
{
const Elf32_Shdr &section = m_elf->getSectionAtIndex(m_sectionIndex);
return section.sh_size;
}
uint32_t ELFSourceFile::ELFDataSource::ProgBitsSegment::getBaseAddress()
{
const Elf32_Shdr &section = m_elf->getSectionAtIndex(m_sectionIndex);
return section.sh_addr;
}
ELFSourceFile::ELFDataSource::NoBitsSegment::NoBitsSegment(ELFDataSource &source, StELFFile *elf, unsigned index)
: DataSource::PatternSegment(source)
, m_elf(elf)
, m_sectionIndex(index)
{
}
unsigned ELFSourceFile::ELFDataSource::NoBitsSegment::getLength()
{
const Elf32_Shdr &section = m_elf->getSectionAtIndex(m_sectionIndex);
return section.sh_size;
}
uint32_t ELFSourceFile::ELFDataSource::NoBitsSegment::getBaseAddress()
{
const Elf32_Shdr &section = m_elf->getSectionAtIndex(m_sectionIndex);
return section.sh_addr;
}

View File

@ -0,0 +1,87 @@
/*
* File: ExcludesListMatcher.cpp
*
* Copyright (c) Freescale Semiconductor, Inc. All rights reserved.
* See included license file for license details.
*/
#include "blfwk/ExcludesListMatcher.h"
using namespace blfwk;
ExcludesListMatcher::ExcludesListMatcher()
: GlobMatcher("")
{
}
ExcludesListMatcher::~ExcludesListMatcher()
{
}
//! \param isInclude True if this pattern is an include, false if it is an exclude.
//! \param pattern String containing the glob pattern.
void ExcludesListMatcher::addPattern(bool isInclude, const std::string &pattern)
{
glob_list_item_t item;
item.m_isInclude = isInclude;
item.m_glob = pattern;
// add to end of list
m_patterns.push_back(item);
}
//! If there are no entries in the match list, the match fails.
//!
//! \param testValue The string to match against the pattern list.
//! \retval true The \a testValue argument matches.
//! \retval false No match was made against the argument.
bool ExcludesListMatcher::match(const std::string &testValue)
{
if (!m_patterns.size())
{
return false;
}
// Iterate over the match list. Includes act as an OR operator, while
// excludes act as an AND operator.
bool didMatch = false;
bool isFirstItem = true;
glob_list_t::iterator it = m_patterns.begin();
for (; it != m_patterns.end(); ++it)
{
glob_list_item_t &item = *it;
// if this pattern is an include and it doesn't match, or
// if this pattern is an exclude and it does match, then the match fails
bool didItemMatch = globMatch(testValue.c_str(), item.m_glob.c_str());
if (item.m_isInclude)
{
// Include
if (isFirstItem)
{
didMatch = didItemMatch;
}
else
{
didMatch = didMatch || didItemMatch;
}
}
else
{
// Exclude
if (isFirstItem)
{
didMatch = !didItemMatch;
}
else
{
didMatch = didMatch && !didItemMatch;
}
}
isFirstItem = false;
}
return didMatch;
}

View File

@ -0,0 +1,103 @@
/*
* File: GHSSecInfo.cpp
*
* Copyright (c) Freescale Semiconductor, Inc. All rights reserved.
* See included license file for license details.
*/
#include "blfwk/GHSSecInfo.h"
#include <stdexcept>
#include "blfwk/Logging.h"
#include "blfwk/EndianUtilities.h"
//! The name of the GHS-specific section info table ELF section.
const char *const kSecInfoSectionName = ".secinfo";
using namespace blfwk;
//! The ELF file passed into this constructor as the \a elf argument must remain
//! valid for the life of this object.
//!
//! \param elf The ELF file parser. An assertion is raised if this is NULL.
GHSSecInfo::GHSSecInfo(StELFFile *elf)
: m_elf(elf)
, m_hasInfo(false)
, m_info(0)
, m_entryCount(0)
{
assert(elf);
// look up the section. if it's not there just leave m_info and m_entryCount to 0
unsigned sectionIndex = m_elf->getIndexOfSectionWithName(kSecInfoSectionName);
if (sectionIndex == SHN_UNDEF)
{
return;
}
// get the section data
const Elf32_Shdr &secInfo = m_elf->getSectionAtIndex(sectionIndex);
if (secInfo.sh_type != SHT_PROGBITS)
{
// .secinfo section isn't the right type, so something is wrong
return;
}
m_hasInfo = true;
m_info = (ghs_secinfo_t *)m_elf->getSectionDataAtIndex(sectionIndex);
m_entryCount = secInfo.sh_size / sizeof(ghs_secinfo_t);
}
//! Looks up \a addr for \a length in the .secinfo array. Only if that address is in the
//! .secinfo array does this section need to be filled. If the section is found but the
//! length does not match the \a length argument, a message is logged at the
//! #Logger::kWarning level.
//!
//! If the .secinfo section is not present in the ELF file, this method always returns
//! true.
//!
//! \param addr The start address of the section to query.
//! \param length The length of the section. If a section with a start address matching
//! \a addr is found, its length must match \a length to be considered.
//!
//! \retval true The section matching \a addr and \a length was found and should be filled.
//! True is also returned when the ELF file does not have a .secinfo section.
//! \retval false The section was not found and should not be filled.
bool GHSSecInfo::isSectionFilled(uint32_t addr, uint32_t length)
{
if (!m_hasInfo)
{
return true;
}
unsigned i;
for (i = 0; i < m_entryCount; ++i)
{
// byte swap these values into host endianness
uint32_t clearAddr = ENDIAN_LITTLE_TO_HOST_U32(m_info[i].m_clearAddr);
uint32_t numBytesToClear = ENDIAN_LITTLE_TO_HOST_U32(m_info[i].m_numBytesToClear);
// we only consider non-zero length clear regions
if ((addr == clearAddr) && (numBytesToClear != 0))
{
// it is an error if the address matches but the length does not
if (length != numBytesToClear)
{
Log::log(Logger::kWarning, "ELF Error: Size mismatch @ sect=%u, .secinfo=%u at addr 0x%08X\n", length,
numBytesToClear, addr);
}
return true;
}
}
return false;
}
//! Simply calls through to isSectionFilled(uint32_t, uint32_t) to determine
//! if \a section should be filled.
//!
//! If the .secinfo section is not present in the ELF file, this method always returns
//! true.
bool GHSSecInfo::isSectionFilled(const Elf32_Shdr &section)
{
return isSectionFilled(section.sh_addr, section.sh_size);
}

View File

@ -0,0 +1,135 @@
/*
* File: GlobMatcher.cpp
*
* Copyright (c) Freescale Semiconductor, Inc. All rights reserved.
* See included license file for license details.
*/
#include "blfwk/GlobMatcher.h"
#ifndef NEGATE
#define NEGATE '^' // std cset negation char
#endif
using namespace blfwk;
//! The glob pattern must match the \e entire test value argument in order
//! for the match to be considered successful. Thus, even if, for example,
//! the pattern matches all but the last character the result will be false.
//!
//! \retval true The test value does match the glob pattern.
//! \retval false The test value does not match the glob pattern.
bool GlobMatcher::match(const std::string &testValue)
{
return globMatch(testValue.c_str(), m_pattern.c_str());
}
//! \note This glob implementation was originally written by ozan s. yigit in
//! December 1994. This is public domain source code.
bool GlobMatcher::globMatch(const char *str, const char *p)
{
int negate;
int match;
int c;
while (*p)
{
if (!*str && *p != '*')
return false;
switch (c = *p++)
{
case '*':
while (*p == '*')
p++;
if (!*p)
return true;
if (*p != '?' && *p != '[' && *p != '\\')
while (*str && *p != *str)
str++;
while (*str)
{
if (globMatch(str, p))
return true;
str++;
}
return false;
case '?':
if (*str)
break;
return false;
// set specification is inclusive, that is [a-z] is a, z and
// everything in between. this means [z-a] may be interpreted
// as a set that contains z, a and nothing in between.
case '[':
if (*p != NEGATE)
negate = false;
else
{
negate = true;
p++;
}
match = false;
while (!match && (c = *p++))
{
if (!*p)
return false;
if (*p == '-')
{ // c-c
if (!*++p)
return false;
if (*p != ']')
{
if (*str == c || *str == *p || (*str > c && *str < *p))
match = true;
}
else
{ // c-]
if (*str >= c)
match = true;
break;
}
}
else
{ // cc or c]
if (c == *str)
match = true;
if (*p != ']')
{
if (*p == *str)
match = true;
}
else
break;
}
}
if (negate == match)
return false;
// if there is a match, skip past the cset and continue on
while (*p && *p != ']')
p++;
if (!*p++) // oops!
return false;
break;
case '\\':
if (*p)
c = *p++;
default:
if (c != *str)
return false;
break;
}
str++;
}
return !*str;
}

View File

@ -0,0 +1,35 @@
/*
* File: HexValues.cpp
*
* Copyright (c) Freescale Semiconductor, Inc. All rights reserved.
* See included license file for license details.
*/
#include "blfwk/HexValues.h"
#include <cctype>
bool isHexDigit(char c)
{
return isdigit(c) || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F');
}
//! \return The integer equivalent to \a c.
//! \retval -1 The character \a c is not a hex character.
uint8_t hexCharToInt(char c)
{
if (c >= '0' && c <= '9')
return c - '0';
else if (c >= 'a' && c <= 'f')
return c - 'a' + 10;
else if (c >= 'A' && c <= 'F')
return c - 'A' + 10;
else
return static_cast<uint8_t>(-1);
}
//! \param encodedByte Must point to at least two ASCII hex characters.
//!
uint8_t hexByteToInt(const char *encodedByte)
{
return (hexCharToInt(encodedByte[0]) << 4) | hexCharToInt(encodedByte[1]);
}

View File

@ -0,0 +1,130 @@
/*
* Copyright 2020 - 2022 NXP
* All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*
*/
#include "blfwk/I2cPeripheral.h"
#include "blfwk/Logging.h"
#include "blfwk/format_string.h"
#include "blfwk/i2c.h"
using namespace blfwk;
////////////////////////////////////////////////////////////////////////////////
// Code
////////////////////////////////////////////////////////////////////////////////
// See I2cPeripheral.h for documentation of this method.
I2cPeripheral::I2cPeripheral(const char *port, long speed, uint8_t address)
: m_fileDescriptor(-1)
{
if (!init(port, address, speed))
{
throw std::runtime_error(format_string("Error: Cannot open I2C port(%s), speed(%d Hz).\n", port, speed));
}
}
// See I2cPeripheral.h for documentation of this method.
bool I2cPeripheral::init(const char *port, long speed, uint8_t address)
{
assert(port);
// Open the port.
m_fileDescriptor = i2c_open(const_cast<char *>(port));
if (m_fileDescriptor == -1)
{
return false;
}
i2c_setup(m_fileDescriptor, speed, address);
// Flush garbage from receive buffer before setting read timeout.
flushRX();
// Set host serial timeout to 10 milliseconds. Higherlevel timeouts are implemented in
// SerialPacketizer.cpp
i2c_set_timeout(m_fileDescriptor, kI2cPeripheral_DefaultReadTimeoutMs);
return true;
}
// See I2cPeripheral.h for documentation of this method.
I2cPeripheral::~I2cPeripheral()
{
if (m_fileDescriptor != -1)
{
i2c_close(m_fileDescriptor);
}
}
// See I2cPeripheral.h for documentation of this method.
status_t I2cPeripheral::read(uint8_t *buffer, uint32_t requestedBytes, uint32_t *actualBytes, uint32_t unused_timeoutMs)
{
assert(buffer);
// Read the requested number of bytes.
int count = i2c_read(m_fileDescriptor, reinterpret_cast<char *>(buffer), requestedBytes);
if (actualBytes)
{
*actualBytes = count;
}
if (Log::getLogger()->getFilterLevel() == Logger::kDebug2)
{
// Log bytes read in hex
Log::debug2("<");
for (int i = 0; i < (int)count; i++)
{
Log::debug2("%02x", buffer[i]);
if (i != (count - 1))
{
Log::debug2(" ");
}
}
Log::debug2(">\n");
}
if (count < (int)requestedBytes)
{
// Anything less than requestedBytes is a timeout error.
return kStatus_Timeout;
}
return kStatus_Success;
}
// See I2cPeripheral.h for documentation of this method.
void I2cPeripheral::flushRX() {}
// See I2cPeripheral.h for documentation of this method.
status_t I2cPeripheral::write(const uint8_t *buffer, uint32_t byteCount)
{
assert(buffer);
if (Log::getLogger()->getFilterLevel() == Logger::kDebug2)
{
// Log bytes written in hex
Log::debug2("[");
for (int i = 0; i < (int)byteCount; i++)
{
Log::debug2("%02x", buffer[i]);
if (i != (byteCount - 1))
{
Log::debug2(" ");
}
}
Log::debug2("]\n");
}
if (i2c_write(m_fileDescriptor, reinterpret_cast<char *>(const_cast<uint8_t *>(buffer)), byteCount) == byteCount)
return kStatus_Success;
else
return kStatus_Fail;
}
////////////////////////////////////////////////////////////////////////////////
// EOF
////////////////////////////////////////////////////////////////////////////////

View File

@ -0,0 +1,225 @@
/*
* Copyright (c) 2013-2015 Freescale Semiconductor, Inc.
* All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <assert.h>
#include <string.h>
#include "blfwk/smart_ptr.h"
#include "blfwk/IntelHexSourceFile.h"
#include "blfwk/Logging.h"
enum
{
//! Size in bytes of the buffer used to collect Intel Hex data records
//! before adding them to the executable image.
//! The address field in each record is 2 bytes, so set the buffer to 64KB.
COLLECTION_BUFFER_SIZE = 64 * 1024
};
using namespace blfwk;
IntelHexSourceFile::IntelHexSourceFile(const std::string &path)
: SourceFile(path, kIntelHexSourceFile)
, m_file(NULL)
, m_image(0)
, m_hasEntryRecord(false)
{
memset(&m_entryRecord, 0, sizeof(m_entryRecord));
}
bool IntelHexSourceFile::isIntelHexFile(std::istream &stream)
{
StIntelHexFile hex(stream);
return hex.isIntelHexFile();
}
void IntelHexSourceFile::open()
{
SourceFile::open();
// create file parser and examine file
m_file = new StIntelHexFile(*m_stream);
m_file->parse();
// build an image of the file
m_image = new StExecutableImage();
buildMemoryImage();
// dispose of file parser object
delete m_file;
m_file = 0;
}
void IntelHexSourceFile::close()
{
assert(m_image);
SourceFile::close();
// dispose of memory image
delete m_image;
m_image = 0;
}
//! \pre The file must be open before this method can be called.
//!
DataSource *IntelHexSourceFile::createDataSource()
{
assert(m_image);
return new MemoryImageDataSource(m_image);
}
//! \retval true The file has an 03 or 05 record.
//! \retval false No entry point is available.
bool IntelHexSourceFile::hasEntryPoint()
{
return m_hasEntryRecord;
}
//! If no entry point is available then 0 is returned instead.
//!
//! \return Entry point address.
//! \retval 0 No entry point is available.
uint32_t IntelHexSourceFile::getEntryPointAddress()
{
if (m_hasEntryRecord)
{
// the address in the record is the entry point
uint32_t address = (m_entryRecord.m_data[0] << 24) | (m_entryRecord.m_data[1] << 16) |
(m_entryRecord.m_data[2] << 8) | (m_entryRecord.m_data[3]);
Log::log(Logger::kDebug2, "entry point address is 0x%08x\n", address);
return address;
}
return 0;
}
//! Scans the Intel Hex of the file looking for data records(00 records). The
//! contents of these records are added to an StExecutableImage object, which
//! coalesces the individual records into contiguous regions of memory.
//!
//! Also looks for 03 and 05 records that contain the entry point. The first
//! match of one of these records is saved off into the #m_entryRecord member.
//!
//! Also looks for 02 and 04 records that contain the extended address. The
//! address in the StExecutableImage object is the combination of extended
//! address and offset in data record.
//!
//! If 01 record, the file end record is detected, the left records would not
//! be handled.
//!
//! \pre The #m_file member must be valid.
//! \pre The #m_image member variable must have been instantiated.
void IntelHexSourceFile::buildMemoryImage()
{
assert(m_file);
assert(m_image);
// Clear the entry point.
m_hasEntryRecord = false;
memset(&m_entryRecord, 0, sizeof(m_entryRecord));
// Allocate buffer to hold data before adding it to the executable image.
// Contiguous records are added to this buffer. When overflowed or when a
// non-contiguous record is encountered the buffer is added to the executable
// image where it will be coalesced further. We don't add records individually
// to the image because coalescing record by record is very slow.
smart_array_ptr<uint8_t> buffer = new uint8_t[COLLECTION_BUFFER_SIZE];
unsigned baseAddress = 0;
unsigned startAddress = 0;
unsigned nextAddress = 0;
unsigned dataLength = 0;
// process IntelHexs
StIntelHexFile::const_iterator it = m_file->getBegin();
for (; it != m_file->getEnd(); it++)
{
const StIntelHexFile::IntelHex &theRecord = *it;
bool isDataRecord = theRecord.m_type == INTELHEX_RECORD_DATA;
bool isEntryRecord = (theRecord.m_type == INTELHEX_RECORD_START_SEGMENT_ADDRESS) ||
(theRecord.m_type == INTELHEX_RECORD_START_LINEAR_ADDRESS);
bool isAddressRecord = (theRecord.m_type == INTELHEX_RECORD_EXTENDED_SEGMENT_ADDRESS) ||
(theRecord.m_type == INTELHEX_RECORD_EXTENDED_LINEAR_ADDRESS);
bool isFileEndRecord = theRecord.m_type == INTELHEX_RECORD_END_OF_FILE;
// handle 00 data record
if (isDataRecord)
{
// If this record's data would overflow the collection buffer, or if the
// record is not contiguous with the rest of the data in the collection
// buffer, then flush the buffer to the executable image and restart.
if (dataLength &&
((dataLength + theRecord.m_dataCount > COLLECTION_BUFFER_SIZE) || (theRecord.m_address != nextAddress)))
{
m_image->addTextRegion(startAddress + baseAddress, buffer, dataLength);
dataLength = 0;
}
// Capture addresses when starting an empty buffer.
if (dataLength == 0)
{
startAddress = theRecord.m_address;
nextAddress = startAddress;
}
// Copy record data into place in the collection buffer and update
// size and address.
memcpy(&buffer[dataLength], theRecord.m_data, theRecord.m_dataCount);
dataLength += theRecord.m_dataCount;
nextAddress += theRecord.m_dataCount;
}
// handle 02, 04 record
else if (isAddressRecord)
{
// If there are data in the collection buffer, then flush the buffer to the executable image.
if (dataLength != 0)
{
m_image->addTextRegion(startAddress + baseAddress, buffer, dataLength);
dataLength = 0;
}
// extended address stored at data field.
baseAddress = (theRecord.m_data[0] << 8) | theRecord.m_data[1];
if (theRecord.m_type == INTELHEX_RECORD_EXTENDED_SEGMENT_ADDRESS)
{
baseAddress <<= 4; // Extended Segment Address Record, left shift 4 bits.
}
else
{
baseAddress <<= 16; // Extended Linear Address Record, left shitf 16 bits.
}
}
// handle 03, 05 record
else if (isEntryRecord)
{
if (!m_hasEntryRecord)
{
// save off the entry point record so we don't have to scan again
memcpy(&m_entryRecord, &theRecord, sizeof(m_entryRecord));
m_hasEntryRecord = true;
}
else
{
// throw an exception when detecting a second entry record
throw StIntelHexParseException("multiple entry record detected");
}
}
// handle 01 record
else if (isFileEndRecord)
{
// if the file end record is detected, stop handling the records.
break;
}
}
// Add any leftover data in the collection buffer to the executable image.
if (dataLength)
{
m_image->addTextRegion(startAddress + baseAddress, buffer, dataLength);
}
}

228
src/blfwk/src/Logging.cpp Normal file
View File

@ -0,0 +1,228 @@
/*
* Copyright (c) 2013-2014 Freescale Semiconductor, Inc.
* Copyright 2015-2020 NXP.
* All rights reserved.
*
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include "blfwk/Logging.h"
// init global logger to null
Logger *Log::s_logger = NULL;
void Logger::log(const char *fmt, ...)
{
va_list args;
va_start(args, fmt);
log(m_level, fmt, args);
va_end(args);
}
void Logger::log(log_level_t level, const char *fmt, ...)
{
va_list args;
va_start(args, fmt);
log(level, fmt, args);
va_end(args);
}
void Logger::log(const char *fmt, va_list args)
{
log(m_level, fmt, args);
}
//! Allocates a temporary 1KB buffer which is used to hold the
//! formatted string.
void Logger::log(log_level_t level, const char *fmt, va_list args)
{
if (level <= m_filter)
{
char *buffer = NULL;
#if WIN32
int l = _vscprintf(fmt, args); // Does not include final NULL char.
buffer = reinterpret_cast<char *>(malloc(l + 1));
if (!buffer)
{
return;
}
vsprintf(buffer, fmt, args);
#else // WIN32
vasprintf(&buffer, fmt, args);
#endif // WIN32
if (buffer)
{
_log(buffer);
free(buffer);
}
}
}
void Log::log(const char *fmt, ...)
{
if (s_logger)
{
va_list args;
va_start(args, fmt);
s_logger->log(fmt, args);
va_end(args);
}
}
void Log::log(const std::string &msg)
{
if (s_logger)
{
s_logger->log(msg);
}
}
void Log::log(Logger::log_level_t level, const char *fmt, ...)
{
if (s_logger)
{
va_list args;
va_start(args, fmt);
s_logger->log(level, fmt, args);
va_end(args);
}
}
void Log::log(Logger::log_level_t level, const std::string &msg)
{
if (s_logger)
{
s_logger->log(level, msg);
}
}
void Log::urgent(const char *fmt, ...)
{
if (s_logger)
{
va_list args;
va_start(args, fmt);
s_logger->log(Logger::kUrgent, fmt, args);
va_end(args);
}
}
void Log::json(const char *fmt, ...)
{
if (s_logger && s_logger->getFilterLevel() == Logger::kJson)
{
va_list args;
va_start(args, fmt);
s_logger->log(Logger::kJson, fmt, args);
va_end(args);
}
}
void Log::error(const char *fmt, ...)
{
if (s_logger)
{
va_list args;
va_start(args, fmt);
s_logger->log(Logger::kError, fmt, args);
va_end(args);
}
}
void Log::warning(const char *fmt, ...)
{
if (s_logger)
{
va_list args;
va_start(args, fmt);
s_logger->log(Logger::kWarning, fmt, args);
va_end(args);
}
}
void Log::info(const char *fmt, ...)
{
if (s_logger)
{
va_list args;
va_start(args, fmt);
s_logger->log(Logger::kInfo, fmt, args);
va_end(args);
}
}
void Log::info2(const char *fmt, ...)
{
if (s_logger)
{
va_list args;
va_start(args, fmt);
s_logger->log(Logger::kInfo2, fmt, args);
va_end(args);
}
}
void Log::debug(const char *fmt, ...)
{
if (s_logger)
{
va_list args;
va_start(args, fmt);
s_logger->log(Logger::kDebug, fmt, args);
va_end(args);
}
}
void Log::debug2(const char *fmt, ...)
{
if (s_logger)
{
va_list args;
va_start(args, fmt);
s_logger->log(Logger::kDebug2, fmt, args);
va_end(args);
}
}
void StdoutLogger::_log(const char *msg)
{
printf("%s", msg);
}
FileLogger::FileLogger(const char *file_path)
: m_file_path(file_path)
, m_logFile(file_path)
{
}
FileLogger::~FileLogger()
{
try
{
m_logFile.close();
}
catch (std::ios_base::failure &e)
{
printf("Error: Failed to close the log file(%s)", e.what());
}
}
void FileLogger::_log(const char *msg)
{
m_logFile << msg;
try
{
m_logFile.flush();
}
catch (std::ios_base::failure &e)
{
printf("Error: Failed to write the log file(%s)", e.what());
}
}

477
src/blfwk/src/LpcUsbSio.cpp Normal file
View File

@ -0,0 +1,477 @@
/*
* Copyright 2020 - 2022 NXP
* All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*
*/
#include "blfwk/Logging.h"
#include "blfwk/LpcUsbSio.h"
#include "blfwk/format_string.h"
using namespace blfwk;
using namespace std;
////////////////////////////////////////////////////////////////////////////////
// Definitions
////////////////////////////////////////////////////////////////////////////////
//! This macro converts a value from KHz to Hz.
#define CONVERT_KHZ_TO_HZ(KHz) (KHz * 1000)
//! This struct maps an error code to a description of that code.
struct LpcUsbSioErrorMessage
{
LPCUSBSIO_ERR_T code; //!< Error code value.
const std::string message; //!< Description of the status.
};
////////////////////////////////////////////////////////////////////////////////
// Variables
////////////////////////////////////////////////////////////////////////////////
//! This variable containing error codes and corresponding descriptions of the codes.
LpcUsbSioErrorMessage s_errorMessage[] = {
{ LPCUSBSIO_OK, "Success" },
{ LPCUSBSIO_ERR_HID_LIB, "HID library error" },
{ LPCUSBSIO_ERR_BAD_HANDLE, "Handle passed to the function is invalid" },
{ LPCUSBSIO_ERR_SYNCHRONIZATION, "Thread Synchronization error" },
{ LPCUSBSIO_ERR_MEM_ALLOC, "Memory Allocation error" },
{ LPCUSBSIO_ERR_MUTEX_CREATE, "Mutex Creation error" },
{ LPCUSBSIO_ERR_FATAL, "Fatal error occurred" },
{ LPCUSBSIO_ERR_I2C_NAK, "Transfer aborted due to NACK" },
{ LPCUSBSIO_ERR_I2C_BUS, "Transfer aborted due to bus error" },
{ LPCUSBSIO_ERR_I2C_SLAVE_NAK, "NAK received after SLA+W or SLA+R" },
{ LPCUSBSIO_ERR_I2C_ARBLOST, "I2C bus arbitration lost to other master" },
{ LPCUSBSIO_ERR_TIMEOUT, "Transaction timed out" },
{ LPCUSBSIO_ERR_INVALID_CMD, "Invalid HID_SIO Request or Request not supported in this version" },
{ LPCUSBSIO_ERR_INVALID_PARAM, "Invalid parameters are provided for the given Request" },
{ LPCUSBSIO_ERR_PARTIAL_DATA, "Partial transfer completed" },
};
////////////////////////////////////////////////////////////////////////////////
// Code
///////////////////////////////////////////////////////////////////////////////
// See LpcUsbSio.h for documentation of this method.
LpcUsbSio::LpcUsbSio(const LpcUsbSio::LpcUsbSioPortConfigData &config)
: m_usbVid(config.usbVid)
, m_usbPid(config.usbPid)
, m_usbString(config.usbString)
, m_usbPath(config.usbPath)
, m_portIndex(config.portIndex)
{
m_portCount = LPCUSBSIO_GetNumPorts(m_usbVid, m_usbPid);
if (m_portCount < 1)
{
throw std::runtime_error(format_string("Error: No LPC USB Serial I/O is detected.\n"));
}
else if (m_portCount < (m_portIndex + 1))
{
throw std::runtime_error(
format_string("Error: Invalid index %d, only %d port(s) available.\n", m_portIndex, m_portCount));
}
m_portHandler = LPCUSBSIO_Open(m_portIndex);
if (m_portHandler == NULL)
{
throw std::runtime_error(
format_string("Error: Failed to open the LPC USB Serial I/O port index %x.\n", m_portIndex));
}
}
// See LpcUsbSio.h for documentation of this method.
LpcUsbSio::~LpcUsbSio()
{
if (m_portHandler)
{
LPCUSBSIO_Close(m_portHandler);
m_portHandler = NULL;
}
}
// See LpcUsbSio.h for documentation of this method.
bool LpcUsbSio::parse(const string_vector_t &params, LpcUsbSio::LpcUsbSioConfigData &config)
{
if (!params[0].compare(0, 3, "spi"))
{
config.function = LpcUsbSio::kFunction_SPI;
// Currently only support one SPI port. Can be extended in the furture.
config.spiConfig.spiPortIndex = 0;
if (params.size() > 1)
{
int32_t port = atoi(params[1].c_str());
if ((port < 0) || (port > 7))
return false;
config.spiConfig.spiSselPort = (uint8_t)port;
}
if (params.size() > 2)
{
int32_t pin = atoi(params[2].c_str());
if ((pin < 0) || (pin > 0x1F))
return false;
config.spiConfig.spiSselPin = (uint8_t)pin;
}
if (params.size() > 3)
{
int32_t spiSpeed = CONVERT_KHZ_TO_HZ(atoi(params[3].c_str()));
if (spiSpeed <= 0)
return false;
config.spiConfig.spiSpeedHz = spiSpeed;
}
if (params.size() > 4)
{
config.spiConfig.spiPolarity = (LpcUsbSio::spi_clock_polarity_t)atoi(params[4].c_str());
}
if (params.size() > 5)
{
config.spiConfig.spiPhase = (LpcUsbSio::spi_clock_phase_t)atoi(params[5].c_str());
}
}
else if (!params[0].compare(0, 3, "i2c"))
{
config.function = LpcUsbSio::kFunction_I2C;
// Currently only support one I2C port. Can be extended in the furture.
config.i2cConfig.i2cPortIndex = 0;
if (params.size() > 1)
{
uint32_t i2cAddress = strtoul(params[1].c_str(), NULL, 16);
if (i2cAddress > 0x7F)
{
i2cAddress &= 0x7F;
Log::warning("Warning: Only 7-bit i2c address is supported, so the effective value is 0x%x\n",
i2cAddress);
}
config.i2cConfig.i2cAddress = (uint8_t)i2cAddress;
}
if (params.size() > 2)
{
int32_t i2cSpeed = CONVERT_KHZ_TO_HZ(atoi(params[2].c_str()));
if (i2cSpeed <= 0)
{
return false;
}
if (i2cSpeed < I2C_CLOCK_FAST_MODE)
{
config.i2cConfig.i2cSpeedHz = I2C_CLOCK_STANDARD_MODE;
}
else if (i2cSpeed < I2C_CLOCK_FAST_MODE_PLUS)
{
config.i2cConfig.i2cSpeedHz = I2C_CLOCK_FAST_MODE;
}
else
{
config.i2cConfig.i2cSpeedHz = I2C_CLOCK_FAST_MODE_PLUS;
}
if ((i2cSpeed != I2C_CLOCK_STANDARD_MODE) && (i2cSpeed != I2C_CLOCK_FAST_MODE) &&
(i2cSpeed != I2C_CLOCK_FAST_MODE_PLUS))
{
Log::warning(
"Warning: Only 100Kbps, 400Kbps and 1Mbps are supported, so the effective speed is %dbps\n",
config.i2cConfig.i2cSpeedHz);
}
}
}
else if (!params[0].compare(0, 4, "gpio"))
{
// Not supported yet.
// config.function = LpcUsbSio::kFunction_GPIO;
return false;
}
else
{
// Error: Invalid BusPal function.
return false;
}
return true;
}
// See LpcUsbSio.h for documentation of this method.
const std::string LpcUsbSio::getError(LPCUSBSIO_ERR_T errorCode)
{
int i;
for (i = 0; i < (sizeof(s_errorMessage) / sizeof(s_errorMessage[0])); ++i)
{
if (errorCode == s_errorMessage[i].code)
{
return s_errorMessage[i].message;
}
}
return format_string("Unknown error code (%d)", errorCode);
}
// See LpcUsbSio.h for documentation of this method.
LpcUsbSioSpi::LpcUsbSioSpi(const LpcUsbSio::LpcUsbSioPortConfigData &portConfig,
const LpcUsbSio::LpcUsbSioSpiConfigData &spiConfig)
: LpcUsbSio(portConfig)
, m_spiPortIndex(spiConfig.spiPortIndex)
, m_spiSselPort(spiConfig.spiSselPort)
, m_spiSselPin(spiConfig.spiSselPin)
{
m_spiPortCount = (int32_t)LPCUSBSIO_GetNumSPIPorts(m_portHandler);
if (m_spiPortCount < 0)
{
throw std::runtime_error(
format_string("Error: Failed to get SPI port count, due to %s.\n", LPCUSBSIO_Error(m_portHandler)));
}
else if (m_spiPortCount == 0)
{
throw std::runtime_error(format_string("Error: No SPI port is detected on current LPC USB Serial I/O.\n"));
}
else if (m_spiPortCount < (m_spiPortIndex + 1))
{
throw std::runtime_error(
format_string("Error: Invalid index %d, only %d port(s) available.\n", m_spiPortIndex, m_spiPortCount));
}
HID_SPI_PORTCONFIG_T spiParam;
spiParam.busSpeed = spiConfig.spiSpeedHz;
spiParam.Options = HID_SPI_CONFIG_OPTION_DATA_SIZE_8 | HID_SPI_CONFIG_OPTION_POL_0 | HID_SPI_CONFIG_OPTION_PHA_0 |
HID_SPI_CONFIG_OPTION_PRE_DELAY(0) | HID_SPI_CONFIG_OPTION_POST_DELAY(0);
if (spiConfig.spiPolarity == LpcUsbSio::kSpiPolarity_ActiveLow)
{
spiParam.Options |= HID_SPI_CONFIG_OPTION_POL_1;
}
if (spiConfig.spiPhase == LpcUsbSio::kSpiPhase_SecondEdge)
{
spiParam.Options |= HID_SPI_CONFIG_OPTION_PHA_1;
}
m_spiPortHandler = SPI_Open(m_portHandler, &spiParam, m_spiPortIndex);
if (m_spiPortHandler == NULL)
{
throw std::runtime_error(
format_string("Error: Failed to open SPI port, due to %s.\n", LPCUSBSIO_Error(m_portHandler)));
}
}
// See LpcUsbSio.h for documentation of this method.
LpcUsbSioSpi::~LpcUsbSioSpi()
{
if (m_spiPortHandler)
{
SPI_Close(m_spiPortHandler);
m_spiPortHandler = NULL;
}
}
// See LpcUsbSio.h for documentation of this method.
uint32_t LpcUsbSioSpi::write(const uint8_t *data, uint32_t byteCount)
{
uint32_t total = 0;
uint8_t *rxBuffer = (uint8_t *)malloc(byteCount);
while (byteCount)
{
uint16_t byteToTransfer = 0;
if (byteCount > UINT16_MAX)
{
byteToTransfer = UINT16_MAX;
}
else
{
byteToTransfer = (uint16_t)byteCount;
}
SPI_XFER_T xfer;
xfer.options = 0;
xfer.length = byteToTransfer;
xfer.txBuff = data + total;
xfer.rxBuff = rxBuffer + total;
xfer.device = LPCUSBSIO_GEN_SPI_DEVICE_NUM(m_spiSselPort, m_spiSselPin);
int result = SPI_Transfer(m_spiPortHandler, &xfer);
if (result < 0)
{
Log::error("Error: Failed to write data via SPI port, due to %x.\n",
LpcUsbSio::getError((LPCUSBSIO_ERR_T)result).c_str());
break;
}
else
{
byteCount -= result;
total += result;
}
}
free(rxBuffer);
return total;
}
// See LpcUsbSio.h for documentation of this method.
uint32_t LpcUsbSioSpi::read(uint8_t *data, uint32_t byteCount)
{
uint32_t total = 0;
uint8_t *txBuffer = (uint8_t *)malloc(byteCount);
memset(txBuffer, 0x0, byteCount);
while (byteCount)
{
uint16_t byteToTransfer = 0;
if (byteCount > UINT16_MAX)
{
byteToTransfer = UINT16_MAX;
}
else
{
byteToTransfer = (uint16_t)byteCount;
}
SPI_XFER_T xfer;
xfer.options = 0;
xfer.length = byteToTransfer;
xfer.txBuff = txBuffer + total;
xfer.rxBuff = data + total;
xfer.device = LPCUSBSIO_GEN_SPI_DEVICE_NUM(m_spiSselPort, m_spiSselPin);
int result = SPI_Transfer(m_spiPortHandler, &xfer);
if (result < 0)
{
Log::error("Error: Failed to read data via SPI port, due to %s.\n",
LpcUsbSio::getError((LPCUSBSIO_ERR_T)result).c_str());
break;
}
else
{
byteCount -= result;
total += result;
}
}
free(txBuffer);
return total;
}
// See LpcUsbSio.h for documentation of this method.
LpcUsbSioI2c::LpcUsbSioI2c(const LpcUsbSio::LpcUsbSioPortConfigData &portConfig,
const LpcUsbSio::LpcUsbSioI2cConfigData &i2cConfig)
: LpcUsbSio(portConfig)
, m_i2cPortIndex(i2cConfig.i2cPortIndex)
, m_i2cAddress(i2cConfig.i2cAddress)
{
m_i2cPortCount = (int32_t)LPCUSBSIO_GetNumSPIPorts(m_portHandler);
if (m_i2cPortCount == 0)
{
throw std::runtime_error(format_string("Error: No I2C port is detected on current LPC USB Serial I/O.\n"));
}
else if (m_i2cPortCount < 0)
{
throw std::runtime_error(
format_string("Error: Failed to get I2C port count, due to %s.\n", LPCUSBSIO_Error(m_portHandler)));
}
else if (m_i2cPortCount < (m_i2cPortIndex + 1))
{
throw std::runtime_error(
format_string("Error: Invalid index %d, only %d port(s) available.\n", m_i2cPortIndex, m_i2cPortCount));
}
I2C_PORTCONFIG_T i2cParam;
i2cParam.ClockRate = i2cConfig.i2cSpeedHz;
i2cParam.Options = 0;
m_i2cPortHandler = I2C_Open(m_portHandler, &i2cParam, m_i2cPortIndex);
if (m_i2cPortHandler == NULL)
{
throw std::runtime_error(
format_string("Error: Failed to open I2C port, due to %s.\n", LPCUSBSIO_Error(m_portHandler)));
}
}
// See LpcUsbSio.h for documentation of this method.
LpcUsbSioI2c::~LpcUsbSioI2c()
{
if (m_i2cPortHandler)
{
I2C_Close(m_i2cPortHandler);
m_i2cPortHandler = NULL;
}
}
// See LpcUsbSio.h for documentation of this method.
uint32_t LpcUsbSioI2c::write(const uint8_t *data, uint32_t byteCount)
{
uint32_t total = 0;
while (byteCount)
{
uint16_t byteToTransfer = 0;
if (byteCount > UINT16_MAX)
{
byteToTransfer = UINT16_MAX;
}
else
{
byteToTransfer = (uint16_t)byteCount;
}
int result = I2C_DeviceWrite(m_i2cPortHandler, m_i2cAddress, (uint8_t *)data + total, byteToTransfer,
I2C_TRANSFER_OPTIONS_START_BIT | I2C_TRANSFER_OPTIONS_STOP_BIT |
I2C_TRANSFER_OPTIONS_BREAK_ON_NACK | I2C_TRANSFER_OPTIONS_NACK_LAST_BYTE);
if (result < 0)
{
Log::error("Error: Failed to write data via I2C port, due to %s.\n",
LpcUsbSio::getError((LPCUSBSIO_ERR_T)result).c_str());
break;
}
else
{
byteCount -= result;
total += result;
}
}
return total;
}
// See LpcUsbSio.h for documentation of this method.
uint32_t LpcUsbSioI2c::read(uint8_t *data, uint32_t byteCount)
{
uint32_t total = 0;
while (byteCount)
{
uint16_t byteToTransfer = 0;
if (byteCount > UINT16_MAX)
{
byteToTransfer = UINT16_MAX;
}
else
{
byteToTransfer = (uint16_t)byteCount;
}
int result = I2C_DeviceRead(m_i2cPortHandler, m_i2cAddress, (uint8_t *)data + total, byteToTransfer,
I2C_TRANSFER_OPTIONS_START_BIT | I2C_TRANSFER_OPTIONS_STOP_BIT |
I2C_TRANSFER_OPTIONS_BREAK_ON_NACK | I2C_TRANSFER_OPTIONS_NACK_LAST_BYTE);
if (result < 0)
{
Log::error("Error: Failed to read data via I2C port, due to %s.\n",
LpcUsbSio::getError((LPCUSBSIO_ERR_T)result).c_str());
break;
}
else
{
byteCount -= result;
total += result;
}
}
return total;
}
////////////////////////////////////////////////////////////////////////////////
// EOF
////////////////////////////////////////////////////////////////////////////////

View File

@ -0,0 +1,137 @@
/*
* Copyright 2020 - 2022 NXP
* All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*
*/
#include "blfwk/Logging.h"
#include "blfwk/LpcUsbSioPeripheral.h"
#include "blfwk/format_string.h"
using namespace blfwk;
using namespace std;
////////////////////////////////////////////////////////////////////////////////
// Code
////////////////////////////////////////////////////////////////////////////////
// See LpcUsbSioPeripheral.h for documentation of this method.
LpcUsbSioPeripheral::LpcUsbSioPeripheral(const LpcUsbSio::LpcUsbSioConfigData &config)
: Peripheral()
{
if (config.function == LpcUsbSio::kFunction_SPI)
{
m_lpcUsbSio = new LpcUsbSioSpi(config.portConfig, config.spiConfig);
}
else if (config.function == LpcUsbSio::kFunction_I2C)
{
m_lpcUsbSio = new LpcUsbSioI2c(config.portConfig, config.i2cConfig);
}
else if (config.function == LpcUsbSio::kFunction_GPIO)
{
// Currently, GPIO function is not supported.
throw std::runtime_error(format_string("Error: GPIO function is not supported yet.\n"));
}
else
{
throw std::runtime_error(format_string("Error: Invalid function of LPC USB Serial I/O.\n"));
}
}
// See LpcUsbSioPeripheral.h for documentation of this method.
LpcUsbSioPeripheral::~LpcUsbSioPeripheral()
{
if (m_lpcUsbSio)
{
delete m_lpcUsbSio;
m_lpcUsbSio = NULL;
}
}
// See LpcUsbSioPeripheral.h for documentation of this method.
status_t LpcUsbSioPeripheral::read(uint8_t *buffer, uint32_t requestedBytes, uint32_t *actualBytes, uint32_t timeoutMs)
{
assert(buffer);
uint32_t count = 0;
if (requestedBytes)
{
// Read the requested number of bytes.
count = m_lpcUsbSio->read(buffer, requestedBytes);
}
if (actualBytes)
{
*actualBytes = count;
}
if (Log::getLogger()->getFilterLevel() == Logger::kDebug2)
{
// Log bytes read in hex
Log::debug2("<");
for (int i = 0; i < (int)count; i++)
{
Log::debug2("%02x", buffer[i]);
if (i != (count - 1))
{
Log::debug2(" ");
}
}
Log::debug2(">\n");
}
if (count == 0)
{
// Nothing got is a timeout error.
return kStatus_Timeout;
}
else if (count != requestedBytes)
{
// Fewer than requested is a failure.
return kStatus_Fail;
}
return kStatus_Success;
}
// See LpcUsbSioPeripheral.h for documentation of this method.
status_t LpcUsbSioPeripheral::write(const uint8_t *buffer, uint32_t byteCount)
{
assert(buffer);
if (Log::getLogger()->getFilterLevel() == Logger::kDebug2)
{
// Log bytes written in hex
Log::debug2("[");
for (int i = 0; i < (int)byteCount; i++)
{
Log::debug2("%02x", buffer[i]);
if (i != (byteCount - 1))
{
Log::debug2(" ");
}
}
Log::debug2("]\n");
}
if (byteCount == 0)
{
return kStatus_Success;
}
uint32_t count = m_lpcUsbSio->write(buffer, byteCount);
if (count < byteCount)
{
// Fewer than requested is a failure.
return kStatus_Fail;
}
return kStatus_Success;
}
////////////////////////////////////////////////////////////////////////////////
// EOF
////////////////////////////////////////////////////////////////////////////////

81
src/blfwk/src/Random.cpp Normal file
View File

@ -0,0 +1,81 @@
/*
* File: Random.cpp
*
* Copyright (c) Freescale Semiconductor, Inc. All rights reserved.
* See included license file for license details.
*/
#include "blfwk/Random.h"
#include <stdexcept>
#ifdef WIN32
#ifndef _WIN32_WINNT
#define _WIN32_WINNT 0x0400
#endif
#include <windows.h>
#include <wincrypt.h>
#else // WIN32
#include <errno.h>
#include <fcntl.h>
#include <unistd.h>
#endif // WIN32
#ifdef WIN32
MicrosoftCryptoProvider::MicrosoftCryptoProvider()
{
if (!CryptAcquireContext(&m_hProvider, 0, 0, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT))
{
throw std::runtime_error("CryptAcquireContext");
}
}
MicrosoftCryptoProvider::~MicrosoftCryptoProvider()
{
CryptReleaseContext(m_hProvider, 0);
}
#endif // WIN32
RandomNumberGenerator::RandomNumberGenerator()
{
#ifndef WIN32
m_fd = open("/dev/urandom", O_RDONLY);
if (m_fd == -1)
{
throw std::runtime_error("open /dev/urandom");
}
#endif // WIN32
}
RandomNumberGenerator::~RandomNumberGenerator()
{
#ifndef WIN32
close(m_fd);
#endif // WIN32
}
uint8_t RandomNumberGenerator::generateByte()
{
uint8_t result;
generateBlock(&result, 1);
return result;
}
void RandomNumberGenerator::generateBlock(uint8_t *output, unsigned count)
{
#ifdef WIN32
#ifdef WORKAROUND_MS_BUG_Q258000
static MicrosoftCryptoProvider m_provider;
#endif
if (!CryptGenRandom(m_provider.GetProviderHandle(), count, output))
{
throw std::runtime_error("CryptGenRandom");
}
#else // WIN32
if (read(m_fd, output, count) != count)
{
throw std::runtime_error("read /dev/urandom");
}
#endif // WIN32
}

View File

@ -0,0 +1,77 @@
/*
* File: RijndaelCTR.cpp
*
* Copyright (c) Freescale Semiconductor, Inc. All rights reserved.
* See included license file for license details.
*/
#include "blfwk/RijndaelCTR.h"
#include "blfwk/rijndael.h"
#include <assert.h>
#include "blfwk/Logging.h"
void logHexArray(Logger::log_level_t level, const uint8_t *bytes, unsigned count);
//! \param key The key to use
//! \param counter The counter to use
RijndaelCTR::RijndaelCTR(const AESKey<128> &key, const AESCounter<128> &counter)
: m_key(key)
, m_counter(counter)
{
}
void RijndaelCTR::decrypt(const uint8_t *data, unsigned length, uint8_t *dest)
{
baseProcess(data, length, dest);
}
void RijndaelCTR::encrypt(const uint8_t *data, unsigned length, uint8_t *dest)
{
baseProcess(data, length, dest);
}
void RijndaelCTR::baseProcess(const uint8_t *data, unsigned length, uint8_t *dest)
{
Rijndael cipher;
unsigned blocks = length / BLOCK_SIZE;
block_t remainder;
AESCounter<128>::counter_t currentCounter;
cipher.init(Rijndael::ECB, Rijndael::Encrypt, m_key, Rijndael::Key16Bytes);
while (blocks--)
{
m_counter.getCounter(&currentCounter);
cipher.blockEncrypt(currentCounter, BLOCK_SIZE * 8, currentCounter);
for (int i = 0; i < BLOCK_SIZE; i++)
{
dest[i] = data[i] ^ currentCounter[i];
}
data += BLOCK_SIZE;
dest += BLOCK_SIZE;
m_counter.incrementCounter(BLOCK_SIZE);
}
if (length % sizeof(block_t))
{
m_counter.getCounter(&currentCounter);
memset(remainder, 0, sizeof(remainder));
memcpy(remainder, data, length % sizeof(block_t));
cipher.blockEncrypt(currentCounter, BLOCK_SIZE * 8, currentCounter);
for (unsigned int i = 0; i < length % sizeof(block_t); i++)
{
remainder[i] = data[i] ^ currentCounter[i];
}
memcpy(dest, remainder, length % sizeof(block_t));
m_counter.incrementCounter(BLOCK_SIZE);
}
}

View File

@ -0,0 +1,80 @@
/*
* Copyright (c) 2013-2014 Freescale Semiconductor, Inc.
* All rights reserved.
*
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <ctype.h>
#include <algorithm>
#include "string.h"
#include "blfwk/stdafx.h"
#include "blfwk/EndianUtilities.h"
#include "blfwk/GHSSecInfo.h"
#include "blfwk/Logging.h"
#include "blfwk/SBSourceFile.h"
using namespace blfwk;
SBSourceFile::SBSourceFile(const std::string &path)
: BinarySourceFile(path, kSBSourceFile)
{
}
SBSourceFile::~SBSourceFile()
{
}
bool SBSourceFile::isSBFile(std::istream &stream)
{
try
{
boot_image_header_t header; //!< Header from the SB boot image.
// readImageHeader
// seek to beginning of the stream/file and read the plaintext header
stream.seekg(0, std::ios_base::beg);
if (stream.read((char *)&header, sizeof(header)).bad())
{
throw SBFileException("failed to read SB image header");
}
header.m_flags = ENDIAN_LITTLE_TO_HOST_U16(header.m_flags);
header.m_imageBlocks = ENDIAN_LITTLE_TO_HOST_U32(header.m_imageBlocks);
header.m_firstBootTagBlock = ENDIAN_LITTLE_TO_HOST_U32(header.m_firstBootTagBlock);
header.m_firstBootableSectionID = ENDIAN_LITTLE_TO_HOST_U32(header.m_firstBootableSectionID);
header.m_keyCount = ENDIAN_LITTLE_TO_HOST_U16(header.m_keyCount);
header.m_keyDictionaryBlock = ENDIAN_LITTLE_TO_HOST_U16(header.m_keyDictionaryBlock);
header.m_headerBlocks = ENDIAN_LITTLE_TO_HOST_U16(header.m_headerBlocks);
header.m_sectionCount = ENDIAN_LITTLE_TO_HOST_U16(header.m_sectionCount);
header.m_sectionHeaderSize = ENDIAN_LITTLE_TO_HOST_U16(header.m_sectionHeaderSize);
header.m_timestamp = ENDIAN_LITTLE_TO_HOST_U64(header.m_timestamp);
// check header signature 1
if (header.m_signature[0] != 'S' || header.m_signature[1] != 'T' || header.m_signature[2] != 'M' ||
header.m_signature[3] != 'P')
{
throw SBFileException("invalid SB signature 1");
}
// check header signature 2 for version 1.1 and greater
if ((header.m_majorVersion > 1 || (header.m_majorVersion == 1 && header.m_minorVersion >= 1)) &&
(header.m_signature2[0] != 's' || header.m_signature2[1] != 'g' || header.m_signature2[2] != 't' ||
header.m_signature2[3] != 'l'))
{
Log::log(Logger::kWarning, "warning: invalid SB signature 2\n");
}
return true;
}
catch (...)
{
return false;
}
}
DataSource *SBSourceFile::createDataSource()
{
throw std::runtime_error("SBSourceFile::createDataSource() has not been implemented.");
}

1002
src/blfwk/src/SDPCommand.cpp Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,99 @@
/*
* Copyright (c) 2015 Freescale Semiconductor, Inc.
* All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include "blfwk/SDPUsbHidPacketizer.h"
#include "blfwk/Logging.h"
using namespace blfwk;
////////////////////////////////////////////////////////////////////////////////
// Code
////////////////////////////////////////////////////////////////////////////////
status_t SDPUsbHidPacketizer::writePacket(const uint8_t *packet, uint32_t byteCount, packet_type_t packetType)
{
assert(m_peripheral);
assert(packetType == kPacketType_Command || packetType == kPacketType_Data);
assert(byteCount);
assert(packet);
uint32_t numBytes = 0;
// Construct report contents.
memset(&m_report, 0, sizeof(m_report));
if (packetType == kPacketType_Command)
{
m_report[0] = kIdReport1; // Report 1 is used to send a command to the device.
numBytes = kReport1SizeBytes;
}
else
{
m_report[0] = kIdReport2; // Report 2 is used to send data to the device.
numBytes = kReport2SizeBytes;
}
memcpy(&m_report[1], packet, byteCount);
return getPeripheral()->write((uint8_t *)&m_report, numBytes, m_packetTimeoutMs);
}
status_t SDPUsbHidPacketizer::readPacket(uint8_t **packet, uint32_t *packetLength, packet_type_t packetType)
{
assert(m_peripheral);
assert(packet);
assert(packetLength);
*packet = NULL;
*packetLength = 0;
// packetType is not used.
// Read report.
uint32_t actualBytes = 0;
uint32_t retryCnt = 0;
do
{
status_t retVal =
m_peripheral->read((uint8_t *)&m_report, sizeof(m_report), &actualBytes, m_packetTimeoutMs);
if (retVal != kStatus_Success)
{
return retVal;
}
if (actualBytes)
{
// Check the report ID.
uint8_t reportId = m_report[0];
if (reportId == kIdReport3)
{
if (actualBytes != kReport3SizeBytes)
{
Log::error("usbhid: received unexpected number of bytes=%x\n", actualBytes);
return kStatus_Fail;
}
}
else if (reportId == kIdReport4)
{
if (actualBytes != kReport4SizeBytes)
{
Log::error("usbhid: received unexpected number of bytes=%x\n", actualBytes);
return kStatus_Fail;
}
}
else
{
Log::error("usbhid: received unexpected report=%x\n", reportId);
return kStatus_Fail;
}
}
} while (!actualBytes && (++retryCnt < kPollPacketMaxRetryCnt));
// Return results.
*packet = &m_report[1];
*packetLength = actualBytes - 1;
return kStatus_Success;
}

Some files were not shown because too many files have changed in this diff Show More