1 /* SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later */ 2 #pragma once 3 4 #ifdef __cplusplus 5 extern "C" { 6 #endif 7 8 #include <stdint.h> 9 #include <stdbool.h> 10 11 #include <libpldm/pldm.h> 12 #include <libpldm/base.h> 13 #include <libpldm/control.h> 14 #include <libpldm/firmware_update.h> 15 16 /** @struct pldm_firmware_component_standalone 17 * 18 * A PLDM Firmware Update Component representation, for use 19 * with pldm_fd_ops callbacks. 20 */ 21 struct pldm_firmware_component_standalone { 22 uint16_t comp_classification; 23 uint16_t comp_identifier; 24 uint8_t comp_classification_index; 25 26 struct pldm_firmware_version active_ver; 27 struct pldm_firmware_version pending_ver; 28 29 bitfield16_t comp_activation_methods; 30 bitfield32_t capabilities_during_update; 31 }; 32 33 /** @struct pldm_firmware_update_component 34 * 35 * An entry for Pass Component Table or Update Component 36 */ 37 struct pldm_firmware_update_component { 38 uint16_t comp_classification; 39 uint16_t comp_identifier; 40 uint8_t comp_classification_index; 41 uint32_t comp_comparison_stamp; 42 struct pldm_firmware_string version; 43 44 /* Not set for PassComponentTable */ 45 uint32_t comp_image_size; 46 /* Not set for PassComponentTable */ 47 bitfield32_t update_option_flags; 48 }; 49 50 /** @struct pldm_fd_ops 51 * 52 * Device-specific callbacks provided by an application, 53 * to define the device update behaviour. 54 * 55 * These will be called by the FD responder when pldm_fd_handle_msg() 56 * or pldm_fd_progress() are called by the application. 57 * 58 * Note that return values vary between functions. Some return a PLDM 59 * completion code or status code which will be sent to the UA, others 60 * return a negative errno on failure. 61 */ 62 struct pldm_fd_ops { 63 /** @brief Provide PLDM descriptors 64 * 65 * @param[in] ctx - callback context 66 * @param[out] ret_descriptors_count - count of descriptors returned 67 * @param[out] ret_descriptors - array of descriptors. 68 * 69 * @return 0 on success, a negative errno value on failure. 70 * (specific errno value is ignored) 71 */ 72 int (*device_identifiers)( 73 void *ctx, uint8_t *ret_descriptors_count, 74 const struct pldm_descriptor **ret_descriptors); 75 76 /** @brief Provide PLDM component table from the application 77 * 78 * @param[in] ctx - callback context 79 * @param[out] ret_entry_count - length of returned ret_entries 80 * @param[out] ret_entries - an array of component pointers 81 * 82 * @return 0 on success, a negative errno value on failure. 83 * (specific errno value is ignored) 84 * 85 * It will be called several times in an update flow. 86 */ 87 int (*components)( 88 void *ctx, uint16_t *ret_entry_count, 89 const struct pldm_firmware_component_standalone ***ret_entries); 90 91 /** @brief Return imageset version from the application 92 * 93 * @param[in] ctx - callback context 94 * @param[out] ret_active - ActiveComponentVersion string 95 * @param[out] ret_active - PendingComponentVersion string 96 * 97 * @return 0 on success, a negative errno value on failure. 98 * (specific errno value is ignored) 99 * 100 * This is used by the FD responder for GetFirmwareParameters. 101 */ 102 int (*imageset_versions)(void *ctx, 103 struct pldm_firmware_string *ret_active, 104 struct pldm_firmware_string *ret_pending); 105 106 /** @brief Called on PassComponentTable or UpdateComponent 107 * 108 * @param[in] ctx - callback context 109 * @param[in] update - will be set for UpdateComponent, and indicates that 110 * an update flow is starting, with the same comp used 111 * for subsequent firmware_data, verify, apply callbacks. 112 * @param[in] comp - the component being used. The FD implementation 113 * will only pass comp that has already been 114 * validated against the pldm_fd_ops.components callback. 115 * 116 * @return PLDM_CRC_COMP_CAN_BE_UPDATED if the component can be updated. 117 */ 118 enum pldm_component_response_codes (*update_component)( 119 void *ctx, bool update, 120 const struct pldm_firmware_update_component *comp); 121 122 /** @brief Provide the transfer size to use 123 * 124 * @param[in] ctx - callback context 125 * @param[in] ua_max_transfer_size - size requested by the UA. 126 * 127 * @return The transfer size to use. This will be clamped to 128 * 32 <= size <= ua_max_transfer_size. 129 * The final data chunk may be shorter. 130 */ 131 uint32_t (*transfer_size)(void *ctx, uint32_t ua_max_transfer_size); 132 133 /* @brief Provides firmware update data from the UA 134 * 135 * @param[in] ctx - callback context 136 * @param[in] offset - offset of the data 137 * @param[in] data - firmware data buffer 138 * @param[in] len - length of data 139 * @param[in] comp - the relevant component 140 * 141 * @return TransferComplete code - either 142 * enum pldm_firmware_update_common_error_codes or 143 * enum pldm_firmware_update_transfer_result_values. 144 * 145 * PLDM_FWUP_TRANSFER_SUCCESS will accept the data chunk, other codes will 146 * abort the transfer, returning that code as TransferComplete 147 */ 148 uint8_t (*firmware_data)( 149 void *ctx, uint32_t offset, const uint8_t *data, uint32_t len, 150 const struct pldm_firmware_update_component *comp); 151 152 /* @brief Requests the application verify the update 153 * 154 * @param[in] ctx - callback context 155 * @param[in] comp - the relevant component 156 * @param[out] ret_pending - set when verify will run asynchronously 157 * @param[out] ret_progress_percent - can optionally be set 158 * during asynchronous verify, 159 * or leave defaulted (101). 160 * 161 * @return VerifyComplete code - either 162 * enum pldm_firmware_update_common_error_codes or 163 * enum pldm_firmware_update_verify_result_values. 164 * 165 * verify() will only be called once all firmware_data (up to the UA-specified 166 * comp_image_size) has been provided. Implementations should check that length 167 * as part of verification, if not already checked. 168 * 169 * If the verify is going to complete asynchronously, implementations set 170 * *ret_pending=true and return PLDM_FWUP_VERIFY_SUCCESS. The FD will then 171 * call verify() again when pldm_fd_progress() is called. 172 */ 173 uint8_t (*verify)(void *ctx, 174 const struct pldm_firmware_update_component *comp, 175 bool *ret_pending, uint8_t *ret_progress_percent); 176 177 /* @brief Requests the application apply the update 178 * 179 * @param[in] ctx - callback context 180 * @param[in] comp - the relevant component 181 * @param[out] ret_pending - set when apply will run asynchronously 182 * @param[out] ret_progress_percent - can optionally be set 183 * during asynchronous apply, 184 * or leave defaulted (101). 185 * 186 * @return ApplyComplete code - either 187 * enum pldm_firmware_update_common_error_codes or 188 * enum pldm_firmware_update_apply_result_values. 189 * 190 * If the apply is going to complete asynchronously, implementations set 191 * *ret_pending=true and return PLDM_FWUP_APPLY_SUCCESS. The FD will then 192 * call apply() again when pldm_fd_progress() is called. 193 */ 194 uint8_t (*apply)(void *ctx, 195 const struct pldm_firmware_update_component *comp, 196 bool *ret_pending, uint8_t *ret_progress_percent); 197 198 /* @brief Activates new firmware 199 * 200 * @param[in] ctx - callback context 201 * @param[in] self_contained - Self Contained Activation is requested 202 * @param[out] ret_estimated_time - a time in seconds to perform 203 * self activation, or may be left as 0. 204 * 205 * @return PLDM completion code 206 * 207 * The device implementation is responsible for checking that 208 * expected components have been updated, returning 209 * PLDM_FWUP_INCOMPLETE_UPDATE if not. 210 */ 211 uint8_t (*activate)(void *ctx, bool self_contained, 212 uint16_t *ret_estimated_time); 213 214 /* @brief Cancel Update Component 215 * 216 * @param[in] ctx - callback context 217 * @param[in] comp - the relevant component 218 * 219 * Called when a component update is cancelled prior to being applied. 220 * This function is called for both Cancel Update Component 221 * and Cancel Update (when a component is currently in progress). */ 222 void (*cancel_update_component)( 223 void *ctx, const struct pldm_firmware_update_component *comp); 224 225 /* @brief Returns a monotonic timestamp 226 * 227 * @param[in] ctx - callback context 228 * 229 * @return timestamp in milliseconds, from an arbitrary origin. 230 Must not go backwards. 231 */ 232 uint64_t (*now)(void *ctx); 233 }; 234 235 /* Static storage can be allocated with 236 * PLDM_SIZEOF_PLDM_FD macro */ 237 #define PLDM_ALIGNOF_PLDM_FD 8 238 struct pldm_fd; 239 240 /** @brief Allocate and initialise a FD responder 241 * 242 * @param[in] ops - Application provided callbacks which define the device 243 * update behaviour 244 * @param[in] ops_ctx - opaque context pointer that will be passed as ctx 245 * to ops callbacks 246 * @param[in] control - an optional struct pldm_control. If provided 247 * the FD responder will set PLDM FW update type 248 * and commands for the control. 249 * 250 * @return a malloced struct pldm_fd, owned by the caller. It should be released 251 * with free(). Returns NULL on failure. 252 * 253 * This will call pldm_fd_setup() on the allocated pldm_fd. 254 */ 255 struct pldm_fd *pldm_fd_new(const struct pldm_fd_ops *ops, void *ops_ctx, 256 struct pldm_control *control); 257 258 /** @brief Initialise a FD responder struct 259 * 260 * @param[in] fd - A pointer to a struct pldm_fd. Applications can allocate this 261 * in static storage of size PLDM_SIZEOF_PLDM_FD if required. 262 * @param[in] pldm_fd_size - applications should pass PLDM_SIZEOF_PLDM_FD, to check 263 * for consistency with the fd pointer. 264 * @param[in] ops - Application provided callbacks which define the device 265 * update behaviour 266 * @param[in] ops_ctx - opaque context pointer that will be passed as ctx 267 * to ops callbacks 268 * @param[in] control - an optional struct pldm_control. If provided 269 * the FD responder will set PLDM FW update type 270 * and commands for the control. 271 * 272 * @return 0 on success, a negative errno value on failure. 273 */ 274 int pldm_fd_setup(struct pldm_fd *fd, size_t pldm_fd_size, 275 const struct pldm_fd_ops *ops, void *ops_ctx, 276 struct pldm_control *control); 277 278 /** @brief Handle a PLDM Firmware Update message 279 * 280 * @param[in] fd 281 * @param[in] remote_address - the source address of the message. 282 * @param[in] in_msg - PLDM incoming message payload 283 * @param[in] in_len - length of in_msg buffer 284 * @param[out] out_msg - PLDM outgoing message payload buffer 285 * @param[inout] out_len - length of available out_msg buffer, will be updated 286 * with the length written to out_msg. 287 * 288 * @return 0 on success, a negative errno value on failure. 289 * 290 * Will return a message to send if out_len > 0 291 * and returning 0. 292 */ 293 int pldm_fd_handle_msg(struct pldm_fd *fd, pldm_tid_t remote_address, 294 const void *in_msg, size_t in_len, void *out_msg, 295 size_t *out_len); 296 297 /** @brief Handle periodic progress events 298 * 299 * @param[in] fd 300 * @param[out] out_msg - PLDM outgoing message payload buffer 301 * @param[inout] out_len - length of available out_msg buffer, will be updated 302 * with the length written to out_msg. 303 * @param[out] remote_address - destination address for the message to send. 304 * This is the address used to initiate the update, 305 * from a previous pldm_fd_handle_msg call. 306 * 307 * @return 0 on success, a negative errno value on failure. 308 * 309 * Will return a message to send to remote_address if out_len > 0 310 * and returning 0. 311 * 312 * This could be called periodically by the application to send retries 313 * during an update flow. A 1 second interval is recommended. 314 */ 315 int pldm_fd_progress(struct pldm_fd *fd, void *out_msg, size_t *out_len, 316 pldm_tid_t *remote_address); 317 318 /** @brief Set update mode idle timeout 319 * 320 * @param[in] fd 321 * @param[in] time - Amount of time before the FD shall exit from update mode 322 * if no command is received, in milliseconds. FD_T1. 323 * Should be 60000-120000 (60-120 sec), initial default is 324 * 120000. 325 * 326 * @return 0 on success, a negative errno value on failure. 327 */ 328 int pldm_fd_set_update_idle_timeout(struct pldm_fd *fd, uint32_t time); 329 330 /** @brief Set request retry time 331 * 332 * @param[in] fd 333 * @param[in] time - Time for retries of Request Firmware Data, 334 * Verify, Apply commands, in miliseconds. FD_T2. 335 * Should be 1000-5000, initial default is 1000. 336 * 337 * Will return a message to send to remote_address if out_len > 0 338 * and returning 0. 339 * 340 * This could be called periodically by the application to send retries 341 * during an update flow. A 1 second interval is recommended. 342 * 343 * @return 0 on success, a negative errno value on failure. 344 */ 345 int pldm_fd_set_request_retry_time(struct pldm_fd *fd, uint32_t time); 346 347 #ifdef __cplusplus 348 } 349 #endif 350