| // Copyright 2024 Google LLC |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // http://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| |
| #pragma once |
| |
| #include "ec_util.hpp" |
| #include "firmware_updater_interface.hpp" |
| #include "host_command_interface.hpp" |
| #include "mtd_util_interface.hpp" |
| #include "payload_update_interface.hpp" |
| #include "sys_interface.hpp" |
| |
| #include <sdbusplus/bus.hpp> |
| #include <xyz/openbmc_project/Control/Hoth/server.hpp> |
| |
| #include <future> |
| |
| namespace google |
| { |
| namespace hoth |
| { |
| |
| template <typename... T> |
| using ServerObject = typename sdbusplus::server::object::object<T...>; |
| using HothInterface = sdbusplus::xyz::openbmc_project::Control::server::Hoth; |
| using HothObject = ServerObject<HothInterface>; |
| |
| /** @class Hoth |
| * @brief Hoth control interface implementation. |
| * @details A concrete implementation for xyz.openbmc_project.Control.Hoth |
| * DBus API. |
| */ |
| class Hoth : public HothObject |
| { |
| public: |
| /** @brief Constructs Hoth Control Interface |
| * |
| * @param[in] bus - The Dbus bus object |
| * @param[in] objPath - The Dbus object path |
| * @param[in] hostCmd - Reference to the host command interface |
| * @param[in] payloadUpdate - Reference to the payload update interface |
| * @param[in] ecutil - Reference to the ec utility interface |
| * @param[in] mtd - Reference to the MTD utility interface |
| * @param[in] sys - Reference to the Sys call interface |
| * @param[in] firmwareUpdater - Reference to the firmware updater interface |
| */ |
| Hoth(sdbusplus::bus::bus& bus, const char* objPath, |
| internal::HostCommand* hostCmd, internal::PayloadUpdate* payloadUpdate, |
| internal::EcUtil* ecutil, internal::FirmwareUpdater* firmwareUpdater) : |
| HothObject(bus, objPath), |
| hostCmd(hostCmd), payloadUpdate(payloadUpdate), ecUtil(ecutil), |
| firmwareUpdater(firmwareUpdater), |
| lastFirmwareUpdateStatus(FirmwareUpdateStatus::None), |
| lastInitiatePayloadStatus(FirmwareUpdateStatus::None), |
| lastSendPayloadStatus(FirmwareUpdateStatus::None), |
| lastVerifyPayloadStatus(FirmwareUpdateStatus::None) |
| { |
| // Nothing to do |
| } |
| |
| /** @brief Implementation for SendHostCommand |
| * Send a host command to Hoth if it isn't banned and return the |
| * response. This will block on Hoth completing its internal operations. |
| * This method should be called from the IPMI HostCommand passthrough. |
| * |
| * @param[in] command - Data to write to Hoth SPI host command offset. |
| * |
| * @return response[std::vector<uint8_t>] - Data read from Hoth SPI host |
| * command offset. |
| */ |
| std::vector<uint8_t> sendHostCommand(std::vector<uint8_t> command) override; |
| |
| /** @brief Implementation for SendTrustedHostCommand |
| * Send a host command to Hoth and return the response. This will block on |
| * Hoth completing its internal operations. This method should be called |
| * from the BMC. |
| * |
| * @param[in] command - Data to write to Hoth SPI host command offset. |
| * |
| * @return response[std::vector<uint8_t>] - Data read from Hoth SPI host |
| * command offset. |
| */ |
| std::vector<uint8_t> |
| sendTrustedHostCommand(std::vector<uint8_t> command) override; |
| |
| /** @brief Implementation for SendHostCommandAsync |
| * Send a host command to Hoth and immediately return without waiting for |
| * response. Caller can either poll with calls to GetHostCommandResponse |
| * until retrieving the response, or wait for a ResponseReady signal. |
| * |
| * @param[in] command - Data to write to Hoth SPI host command offset. |
| * |
| * @return callToken[uint64_t] - The representation for the call made, if |
| * it was posted |
| */ |
| uint64_t sendHostCommandAsync(std::vector<uint8_t> command) override; |
| |
| /** @brief Implementation for GetHostCommandResponse |
| * Read the response from Hoth mailbox. |
| * |
| * @param[in] callToken - The token returned from SendHostCommandAsync() |
| * |
| * @return response[std::vector<uint8_t>] - Data read from Hoth SPI host |
| * command offset. |
| */ |
| std::vector<uint8_t> getHostCommandResponse(uint64_t callToken) override; |
| |
| /** @brief Implementation for UpdateFirmware |
| * Write given firmware data to the Hoth firmware partition in EEPROM. |
| * |
| * @param[in] firmwareData - Hoth firmware image. |
| */ |
| void updateFirmware(std::vector<uint8_t> firmwareData) override; |
| |
| /** @brief Implementation for SpiWrite |
| * Write the byte data to the specified address in EEPROM. |
| * |
| * @param[in] address - Address to start writing from |
| * @param[in] data - Data to be written |
| */ |
| void spiWrite(uint32_t address, std::vector<uint8_t> data) override; |
| |
| /** @brief Implementation for GetFirmwareUpdateStatus |
| * Get the status of the firmware update process. |
| * |
| * @return status[FirmwareUpdateStatus] - Status of the firmware update |
| */ |
| FirmwareUpdateStatus getFirmwareUpdateStatus() override; |
| |
| /** @brief Implementation for InitiatePayload |
| * Initiates erasure of the EEPROM staging area. Note that this will lock |
| * up access to Hoth for an extended time and may go over the kernel's SPI |
| * write timeout. Calling multiple small ErasePayload is recommended. |
| */ |
| void initiatePayload() override; |
| |
| /** @brief Implementation for GetInitiatePayloadStatus |
| * Get the status of the payload initiation process. |
| * |
| * @return status[FirmwareUpdateStatus] - Status of the payload initiation |
| */ |
| FirmwareUpdateStatus getInitiatePayloadStatus() override; |
| |
| /** @brief Implementation for SendPayload |
| * Chunk and send the binary specified in the image path |
| * |
| * @param[in] imagePath - Firmware image path |
| */ |
| void sendPayload(std::string imagePath) override; |
| |
| /** @brief Implementation for GetSendPayloadStatus |
| * Get the status of the send payload process. |
| * |
| * @return status[FirmwareUpdateStatus] - Status of the send payload |
| * process. |
| */ |
| FirmwareUpdateStatus getSendPayloadStatus() override; |
| |
| /** @brief Implementation for ErasePayload |
| * Erases the given size starting at the specified offset of the staging |
| * partition. |
| * |
| * @param[in] offset - Offset of the staging partition to start erasing |
| * from. |
| * @param[in] size - Size of the staging partition to erase. |
| */ |
| void erasePayload(uint32_t offset, uint32_t size) override; |
| |
| /** @brief Implementation for eraseAndSendStaticWPPayload |
| * Erases and writes only the static and write protected regions of the |
| * image provided. |
| * |
| * @param[in] imagePath - Firmware image path |
| */ |
| void eraseAndSendStaticWPPayload(std::string imagePath) override; |
| |
| /** @brief Implementation for VerifyPayload |
| * Initiates the verification process without activating the staging area. |
| */ |
| void verifyPayload() override; |
| |
| /** @brief Implementation for GetInitiatePayloadStatus |
| * Get the status of the payload verification process. |
| * |
| * @return status[FirmwareUpdateStatus] - Status of the payload |
| * verification |
| */ |
| FirmwareUpdateStatus getVerifyPayloadStatus() override; |
| |
| /** @brief Implementation for ActivatePayload |
| * Activates the staging area as persistent or non-persistent for next boot |
| * if verification was successful. |
| * |
| * @param[in] makePersistent - Flag to determine whether to activate the |
| * staged image as persistent or non-persistent for next boot. |
| */ |
| void activatePayload(bool makePersistent) override; |
| |
| /** @brief Implementation for DeactivatePayload |
| * Deactivates the staging area |
| * |
| */ |
| void deactivatePayload() override; |
| |
| /** @brief Implementation for GetPayloadSize |
| * |
| * @return The size of the payload region |
| */ |
| uint32_t getPayloadSize() override; |
| |
| /** @brief Implementation for Confirm |
| * Prevents hoth from rolling back and using the previous image. When an |
| * image can be comfirmed to be working well, this command is given, which |
| * disarms the hoth watchdog. |
| */ |
| void confirm() override; |
| |
| /** @brief Implementation for GetTotalBootTime. |
| * |
| * @return Time spent in microseconds from reset to HVNGOOD. |
| */ |
| uint32_t getTotalBootTime() override; |
| |
| /** @brief Implementation for GetFirmwareUpdateTime. |
| * |
| * @return Time spent in microseconds in the self update routine. |
| */ |
| uint32_t getFirmwareUpdateTime() override; |
| |
| /** @brief Implementation for GetFirmwareMirroringTime. |
| * |
| * @return Time spent in microseconds in mirroing the self-update. |
| */ |
| uint32_t getFirmwareMirroringTime() override; |
| |
| /** @brief Implementation for GetPayloadValidationTime. |
| * |
| * @return Time spent in microseconds in validating the payload. |
| */ |
| uint32_t getPayloadValidationTime() override; |
| |
| /** |
| * @brief Implementation for CollectHothLogs |
| * |
| */ |
| void collectHothLogs() override; |
| |
| /** |
| * @brief Trigger Uart log scheduler if not already working over Dbus |
| */ |
| void collectUartLogs() override; |
| |
| /** |
| * @brief Manual Stop to Uart log scheduler over Dbus |
| */ |
| void stopUartLogs() override; |
| |
| private: |
| /** @brief Connection to Hoth for sending and receiving host commands */ |
| internal::HostCommand* hostCmd = nullptr; |
| |
| /** @brief Payload object to conduct payload update with Hoth */ |
| internal::PayloadUpdate* payloadUpdate = nullptr; |
| |
| /** @brief EC utility object to access the utility function from Hoth */ |
| internal::EcUtil* ecUtil = nullptr; |
| |
| /** @brief FirmwareUpdater object */ |
| internal::FirmwareUpdater* firmwareUpdater = nullptr; |
| |
| /** @brief Wrapper function to determine the status of an async thread |
| * |
| * @param[in] asyncFuture - Pointer to the async thread of interest |
| * @return status[FirmwareUpdateStatus] - Status of the async thread |
| */ |
| static FirmwareUpdateStatus getAsyncStatus(std::future<void>* asyncFuture); |
| |
| /** @brief Check for any ongoing payload async threads |
| * If an ongoing payload async thread is found, throw an exception via elog |
| */ |
| void checkForOngoingPayload(); |
| |
| /** @brief Check for any ongoing SPI write threads |
| * If an SPI write async thread is found, throw an exception via elog |
| */ |
| void checkForOngoingSpiWrite(); |
| |
| /** @brief Future object for initiate paylaod */ |
| std::future<void> futInitiatePayload; |
| |
| /** @brief Future object for send payload */ |
| std::future<void> futSendPayload; |
| |
| /** @brief Future object for verify payload */ |
| std::future<void> futVerifyPayload; |
| |
| /** @brief Future object for SPI write */ |
| std::future<void> futSpiWrite; |
| |
| /** @brief Last FirmwareUpdateStatus checked for firmware update */ |
| FirmwareUpdateStatus lastFirmwareUpdateStatus; |
| |
| /** @brief Last FirmwareUpdateStatus checked for initiate payload */ |
| FirmwareUpdateStatus lastInitiatePayloadStatus; |
| |
| /** @brief Last FirmwareUpdateStatus checked for send payload */ |
| FirmwareUpdateStatus lastSendPayloadStatus; |
| |
| /** @brief Last FirmwareUpdateStatus checked for verify payload */ |
| FirmwareUpdateStatus lastVerifyPayloadStatus; |
| }; |
| |
| } // namespace hoth |
| } // namespace google |