diff options
author | Matthew Raybuck <matthew.raybuck@ibm.com> | 2019-07-23 15:17:20 -0500 |
---|---|---|
committer | Daniel M Crowell <dcrowell@us.ibm.com> | 2019-08-09 09:55:40 -0500 |
commit | c03117c7bb4915a4aa9dd2bc22140ded2e301b84 (patch) | |
tree | aacfcc7ac6947b93bc66171b50c6cdb14df04d71 /src/usr/isteps/nvdimm/bpm_update.H | |
parent | 0f0b7c641abb16561970c51371ecbfb9f254481b (diff) | |
download | talos-hostboot-c03117c7bb4915a4aa9dd2bc22140ded2e301b84.tar.gz talos-hostboot-c03117c7bb4915a4aa9dd2bc22140ded2e301b84.zip |
Add BPM config update procedure
Adds the config portion of the BPM updates. This includes missing
requirements from BSL version 1.4. Currently, only BSL 1.4 is supported
by the BPM update procedure. If a BSL version is unsupported, then the
update will be skipped.
Change-Id: I063786bad0723441da52db95b815a32b6498df4c
RTC: 212446
Reviewed-on: http://rchgit01.rchland.ibm.com/gerrit1/80925
Reviewed-by: Christian R Geddes <crgeddes@us.ibm.com>
Tested-by: Jenkins Server <pfd-jenkins+hostboot@us.ibm.com>
Reviewed-by: Roland Veloz <rveloz@us.ibm.com>
Tested-by: Jenkins OP Build CI <op-jenkins+hostboot@us.ibm.com>
Tested-by: FSP CI Jenkins <fsp-CI-jenkins+hostboot@us.ibm.com>
Tested-by: Jenkins OP HW <op-hw-jenkins+hostboot@us.ibm.com>
Reviewed-by: Daniel M Crowell <dcrowell@us.ibm.com>
Diffstat (limited to 'src/usr/isteps/nvdimm/bpm_update.H')
-rw-r--r-- | src/usr/isteps/nvdimm/bpm_update.H | 377 |
1 files changed, 374 insertions, 3 deletions
diff --git a/src/usr/isteps/nvdimm/bpm_update.H b/src/usr/isteps/nvdimm/bpm_update.H index a1ed79c05..f602968fe 100644 --- a/src/usr/isteps/nvdimm/bpm_update.H +++ b/src/usr/isteps/nvdimm/bpm_update.H @@ -69,6 +69,41 @@ enum COMMAND : uint8_t BPM_LOCAL = 0xFF, }; +// These are the various response codes returned by the BPM after the +// BSL_CRC_CHECK command is sent at the end of the update procedure. +enum COMMAND_BSL_CRC_CHECK_RESPONSE_CODES : uint16_t +{ + // The updated firmware is set up with all necessary loading parameters to + // load and execute upon reset. + SUCCESSFUL_OPERATION = 0x00, + + // Error setting up the necessary loading parameters for the updated + // firmware image. + MEMORY_WRITE_CHECK_FAILED = 0x01, + + // The command was attempted without unlocking the BSL with the password. + BSL_LOCKED = 0x04, + + // Error setting up the necessary loading parameters for the updated + // firmware image. + WRITE_FORBIDDEN = 0x06, + + // The checksum validation of the updated firmware image failed. The + // calculated checksum doesn't match the checksum data provided @FF7A in the + // firmware image file. + VERIFY_MISMATCH = 0x09, + + // The firmware image start address given for the command is wrong. + PARAMETER_ERROR = 0x0A, + + // Firmware image file used for the update doesn't hae the checksum data + // defined @FF7A + MAIN_FW_NOT_SUPPORT_CRC_CHECK = 0x0B, +}; + +// BSL versions that this code supports. +const uint8_t BSL_VERSION_1_4 = 0x14; + // The operator types for the BPM_CMD_STATUS register enum COMMAND_STATUS_REGISTER_OP_TYPES : uint8_t { @@ -98,6 +133,24 @@ struct firmware_image_block typedef firmware_image_block firmware_image_block_t; +// Used to overlay onto the LID image +struct config_image_fragment +{ + // The fragment size is the size of iv_data. + uint8_t iv_fragmentSize; + + // The offset where the first byte in iv_data should begin overwritting the + // BPM config data in the BPM configuration segment dump buffer. + uint16_t iv_offset; + + // A variable sized array of config segment data. + char iv_data[0]; + +} PACKED; + +typedef config_image_fragment config_image_fragment_t; + + /* Max payload size is 26 bytes * 4 bytes: header * 1 byte: sync byte @@ -125,6 +178,15 @@ extern const uint8_t PAYLOAD_HEADER_SIZE; // automatically sends the sync byte ahead of the payload. extern const uint8_t SYNC_BYTE; +// Maximum size of any segment in the config data section +constexpr size_t SEGMENT_SIZE = 128; + +// Maximum size of the config data section. +constexpr size_t ALL_SEGMENTS_SIZE = 512; + +// Number of magic registers for the BPM +constexpr size_t NUM_MAGIC_REGISTERS = 2; + typedef std::vector<uint8_t> payload_t; @@ -223,8 +285,90 @@ private: size_t iv_lidImageSize; }; + +class BpmConfigLidImage +{ +public: + + /** + * @brief Constructor that sets access to LID information + * + * @param[in] i_lidImageAddr virtual address where LID was loaded + * @param[in] i_size size of the loaded LID + */ + BpmConfigLidImage(void * const i_lidImageAddr, size_t i_size); + + /** + * @brief Returns the version of the config binary as a uint16_t. There isn't + * a way to check the version of the config data on the BPM but the + * config binary still has the version of the flash image it + * originally came from. + * + * @return uint16_t version of the firmware image as MMmm. + * MM = major version, mm = minor. + */ + uint16_t getVersion() const; + + /** + * @brief Returns the number of fragments in the LID image. + * + */ + uint16_t getNumberOfFragments() const; + + /** + * @brief Returns a pointer to the first fragment in LID image. + */ + void const * getFirstFragment() const; + + /* The binary will be organized in the following way: + * Byte 1: Major version number (MM) + * Byte 2: Minor version number (mm) + * Byte 3: N number of fragments in the file (NN) + * Byte 4-EOF: Fragments of the form: + * FRAGMENT_SIZE Byte 1: X number of bytes in fragment data + * section. (XX) + * INDEX_OFFSET Byte 2-3: Each BPM's config section is unique + * to itself. So, during the update + * the contents of a BPM's config data + * will be dumped into a buffer. + * These two bytes will be used as an + * offset into that buffer from which + * overwritting will take place. + * (IN DX) + * DATA_BYTES Byte 4-X: Fragment data bytes to be written + * at the INDEX_OFFSET in the dumped + * config data buffer. (DD) + * + * Example file output: + * 01 05 01 04 01 28 6a 14 31 80 + * MM mm NN XX IN DX DD DD DD DD + */ + typedef struct config_image_header + { + uint8_t iv_versionMajor; + uint8_t iv_versionMinor; + uint16_t iv_numberOfFragments; + } config_image_header_t; + +private: + + // Pointer to the LID image allocated outside of the class + void * const iv_lidImage; + + // The size of the LID image. + size_t iv_lidImageSize; +}; + class Bpm { + /* + * The Bpm can either be in Bootstrap Loader (BSL) mode or not. Many of + * member functions utilize BSL mode for the update procedure and must + * therefore be in BSL mode to succeed. Other functions perform operations + * that will not work in BSL mode since that mode is strictly for updating + * the device and turns of some functionality while in that mode. The "mode" + * the BPM must be in is given in the function brief description. + */ public: @@ -241,7 +385,24 @@ public: * @return errlHndl_t nullptr on success. Otherwise, pointer to an * errlEntry. */ - errlHndl_t runUpdate(BpmFirmwareLidImage i_image); + errlHndl_t runUpdate(BpmFirmwareLidImage i_fwImage, + BpmConfigLidImage i_configImage); + + /** + * @brief At most, one full update retry should occur in some + * circumstances. If one of those occurances happens then the + * member iv_attemptAnotherUpdate will be set to true. Otherwise, it + * will remain false. + * + * @return bool true if another update should be attempted. + * Otherwise, false. + */ + bool attemptAnotherUpdate(); + + /** + * @brief returns the nvdimm that is associated with this BPM. + */ + const TARGETING::TargetHandle_t getNvdimm(); private: @@ -250,6 +411,21 @@ private: // The Bootstrap Loader version of the BPM uint8_t iv_bslVersion; + uint16_t iv_firmwareStartAddress; + + // Keeps track of if the update should be attempted again. + bool iv_attemptAnotherUpdate; + + // Buffers for the segment data in case another update attempt is needed. + // If the first update fails there won't be any running firmware on the + // device which is required to dump the segment data. + uint8_t iv_segmentD[SEGMENT_SIZE]; + uint8_t iv_segmentB[SEGMENT_SIZE]; + + // Keeps track if the segments have been merged with the flash image data + // yet. + bool iv_segmentDMerged; + bool iv_segmentBMerged; /** * @brief Gets the BSL version from the BPM and sets the iv_bslVersion @@ -288,11 +464,11 @@ private: uint8_t i_opType); /** - * @brief This function issues a BCL command to the BPM by setting up a + * @brief This function issues a BSP command to the BPM by setting up a * payload containing only that command and then calling the * issueCommand function that accepts a payload as an argument. * - * NOTE: Since the BCL command is not a BSL command, it doesn't need + * NOTE: Since the BSP command is not a BSL command, it doesn't need * to be formatted as a BSL payload but it still must be written to * the BPM_REG_PAYLOAD_START register. * @@ -345,6 +521,13 @@ private: errlHndl_t updateFirmware(BpmFirmwareLidImage i_image); /** + * @brief Executes the config portion of the BPM update. + * + * @return errlHndl_t nullptr on success. Otherwise, an Error. + */ + errlHndl_t updateConfig(); + + /** * @brief Commands the BPM to enter BSL mode to allow for BSL commands to be * executed. * @@ -409,6 +592,129 @@ private: errlHndl_t resetDevice(); /** + * @brief Write to the BPM register via the SCAP registers + * + * @param[in] i_reg The BPM register to write to. + * + * @param[in] i_data The data to write to the given register. + * + * @return errlHndl_t nullptr on success. Otherwise, an error. + */ + errlHndl_t writeViaScapRegister(uint8_t i_reg, uint8_t i_data); + + /** + * @brief Reads the BPM register via the SCAP registers + * + * @param[in] i_reg The BPM register to read from. + * + * @param[in/out] io_data The data that was in the given register. + * + * @return errlHndl_t nullptr on success. Otherwise, an error. + */ + errlHndl_t readViaScapRegister(uint8_t i_reg, uint8_t & io_data); + + /** + * @brief Disables write protection on the BPM by sending the password + * sequence to I2C_REG_PROTECT + * + * @return errlHndl_t nullptr on success. Otherwise, an error. + */ + errlHndl_t disableWriteProtection(); + + /** + * @brief Many operations performed on the BPM require the magic registers + * to have specific values written in them. This function acts as a + * helper to facilitate that process. + * + * NOTE: Write protection on the BPM must be disabled, otherwise + * this function will fail. + * + * @param[in] i_magicValues The pair of magic values to be written to + * BPM_MAGIC_REG1 and BPM_MAGIC_REG2 + * respectively. + * + * @return errlHndl_t nullptr on success. Otherwise, an error. + */ + errlHndl_t writeToMagicRegisters( + uint8_t const (&i_magicValues)[NUM_MAGIC_REGISTERS]); + + /** + * @brief Dumps the given segment data from the BPM. CANNOT be in BSL mode. + * + * @param[in] i_segmentCode The segment code that corresponds to the + * segment to dump from the BPM. + * + * @param[out] o_buffer A pointer to the buffer to fill with segment + * data. Must be SEGMENT_SIZE in size. + * + * @return errlHndl_t nullptr on success. Otherwise, an error + * + */ + errlHndl_t dumpSegment(uint16_t i_segmentCode, + uint8_t (&o_buffer)[SEGMENT_SIZE]); + + /** + * @brief Merges the segment data dumped from the BPM with the segment data + * fragments present in the BpmConfigLidImage that correspond to the + * given segment code. + * + * @param[in] i_configImage The image that holds the fragments of + * segment data. + * + * @param[in] i_segmentCode The segment code that corresponds to the + * segment to dump from the BPM. + * + * @param[out] o_buffer The merged segment data for the BPM. + * Must be SEGMENT_SIZE in length. + * + * @return errlHndl_t nullptr on success. Otherwise, an error. + */ + errlHndl_t mergeSegment(BpmConfigLidImage i_configImage, + uint16_t i_segmentCode, + uint8_t (&o_buffer)[SEGMENT_SIZE]); + + /** + * @brief Commands the BPM to erase the segment data on the BPM using the + * given segment code to tell it which to erase. + * The BPM must be in BSL mode for this function to work. + * + * @param[in] i_segmentCode The segment from the config data section to + * erase. + * + * @return errlHndl_t nullptr on success. Otherwise, an error. + */ + errlHndl_t eraseSegment(uint16_t i_segmentCode); + + /** + * @brief Writes the segment data from the buffer to the BPM using the + * given segment code to determine which segment the data belongs + * to. The BPM must be in BSL mode for this function to work. + * + * @param[in] i_buffer The segment data to write to the BPM. + * + * @param[in] i_segmentCode The segment from the config data section the + * data belongs to. + * + * @return errlHndl_t nullptr on success. Otherwise, an error. + */ + errlHndl_t writeSegment(uint8_t const (&i_buffer)[SEGMENT_SIZE], + uint16_t i_segmentCode); + + /** + * @brief Dumps segment D and B data from the BPM and merges it with the + * data from the config image to create the unique updated segments + * for this BPM. The BPM CANNOT be in BSL mode for this function to + * work because the data is dumped using SCAP registers. There must + * also be working firmware on the device otherwise this will fail. + * + * @param[in] i_configImage The config image that has the fragments to + * merge into the BPM's existing segment data. + * + * @return errlHndl_t nullptr on success. Otherwise, an error. + */ + errlHndl_t preprocessSegments(BpmConfigLidImage i_configImage); + + /** * @brief A helper function used to wait for the command status bit to reset * after a command is executed. * @@ -422,6 +728,41 @@ private: command_status_register_t i_commandStatus); /** + * @brief Helper function for the SCAP register functions that will poll + * the busy bit in SCAP_STATUS until it is zero. + * + * @return errlHndl_t nullptr on success. Otherwise, an error. + */ + errlHndl_t waitForBusyBit(); + + /** + * @brief Starting with BSL version 1.4 it is necessary to check the CRC of + * the firmware image once it has been written to the BPM. If this + * is not done or fails to succeed then the firmware image will not + * be loaded and executed by the BPM. If the CRC check fails then + * the update must be attempted again. + * Must be in BSL mode. + * + * @return errlHndl_t nullptr on success. Otherwise, an error. + */ + errlHndl_t checkFirmwareCrc(); + + /** + * @brief After a command is sent to the BPM to request info from it this + * function processes the response and returns it to the caller. + * Must be in BSL mode. + * + * @param[in] o_responseData The buffer to be filled with the + * response data from the BPM. + * + * @param[in] i_responseSize The size of the buffer to be filled. + * + * @return errlHndl_t nullptr on success. Otherwise, an error. + */ + errlHndl_t getResponse(uint8_t * o_responseData, + uint8_t i_responseSize); + + /** * @brief Calculates the CRC16 bytes for the BSL payload. This CRC differs * from the NVDIMM CRC calculation in that the initial value is * 0xFFFF instead of 0x0000. @@ -442,6 +783,36 @@ private: }; +typedef std::vector<Bpm> bpmList_t; + +/** + * @brief Runs the firmware and config updates on the list of BPMs given. + * + * @param[in] i_16gb_BPMs The list of BPMs sitting on 16gb NVDIMMs that + * potentially need to be updated. + * + * @param[in] i_32gb_BPMs The list of BPMs sitting on 32gb NVDIMMs that + * potentially need to be updated. + * + * @param[in] i_16gb_fwImage The firmware image associated with BPMs sitting + * on 16gb NVDIMMs. + * + * @param[in] i_32gb_fwImage The firmware image associated with BPMs sitting + * on 32gb NVDIMMs. + * + * @param[in] i_16gb_configImage The configuration data associated with BPMs + * sitting on 16gb NVDIMMs. + * + * @param[in] i_32gb_configImage The configuration data associated with BPMs + * sitting on 32gb NVDIMMs. + * + */ +void runBpmUpdates(bpmList_t * const i_16gb_BPMs, + bpmList_t * const i_32gb_BPMs, + BpmFirmwareLidImage * const i_16gb_fwImage, + BpmFirmwareLidImage * const i_32gb_fwImage, + BpmConfigLidImage * const i_16gb_configImage, + BpmConfigLidImage * const i_32gb_configImage); }; // end of BPM namespace }; // end of NVDIMM namespace |