1 #pragma once 2 3 #include "config.h" 4 5 #include "libpldmresponder/pdr.hpp" 6 #include "libpldmresponder/utils.hpp" 7 8 #include <stdint.h> 9 10 #include <map> 11 12 #include "libpldm/platform.h" 13 #include "libpldm/states.h" 14 15 namespace pldm 16 { 17 18 using Response = std::vector<uint8_t>; 19 20 namespace responder 21 { 22 23 namespace platform 24 { 25 26 /** @brief Register handlers for commands from the platform spec 27 */ 28 void registerHandlers(); 29 30 } // namespace platform 31 32 /** @brief Handler for GetPDR 33 * 34 * @param[in] request - Request message payload 35 * @param[in] payloadLength - Request payload length 36 * @param[out] Response - Response message written here 37 */ 38 Response getPDR(const pldm_msg* request, size_t payloadLength); 39 40 /** @brief Handler for setStateEffecterStates 41 * 42 * @param[in] request - Request message 43 * @param[in] payloadLength - Request payload length 44 * @return Response - PLDM Response message 45 */ 46 Response setStateEffecterStates(const pldm_msg* request, size_t payloadLength); 47 48 /** @brief Function to set the effecter requested by pldm requester 49 * @param[in] dBusIntf - The interface object 50 * @param[in] effecterId - Effecter ID sent by the requester to act on 51 * @param[in] stateField - The state field data for each of the states, equal 52 * to composite effecter count in number 53 * @return - Success or failure in setting the states. Returns failure in terms 54 * of PLDM completion codes if atleast one state fails to be set 55 */ 56 template <class DBusInterface> 57 int setStateEffecterStatesHandler( 58 const DBusInterface& dBusIntf, effecter::Id effecterId, 59 const std::vector<set_effecter_state_field>& stateField) 60 { 61 using namespace std::string_literals; 62 using DBusProperty = std::variant<std::string, bool>; 63 using StateSetId = uint16_t; 64 using StateSetNum = uint8_t; 65 using PropertyMap = 66 std::map<StateSetId, std::map<StateSetNum, DBusProperty>>; 67 static const PropertyMap stateNumToDbusProp = { 68 {PLDM_BOOT_PROGRESS_STATE, 69 {{PLDM_BOOT_NOT_ACTIVE, 70 "xyz.openbmc_project.State.OperatingSystem.Status.OSStatus." 71 "Standby"s}, 72 {PLDM_BOOT_COMPLETED, 73 "xyz.openbmc_project.State.OperatingSystem.Status.OSStatus." 74 "BootComplete"s}}}, 75 }; 76 using namespace phosphor::logging; 77 using namespace pldm::responder::pdr; 78 using namespace pldm::responder::effecter::dbus_mapping; 79 80 state_effecter_possible_states* states = nullptr; 81 pldm_state_effecter_pdr* pdr = nullptr; 82 uint8_t compEffecterCnt = stateField.size(); 83 uint32_t recordHndl{}; 84 Repo& pdrRepo = get(PDR_JSONS_DIR); 85 pdr::Entry pdrEntry{}; 86 87 while (!pdr) 88 { 89 pdrEntry = pdrRepo.at(recordHndl); 90 pldm_pdr_hdr* header = reinterpret_cast<pldm_pdr_hdr*>(pdrEntry.data()); 91 if (header->type != PLDM_STATE_EFFECTER_PDR) 92 { 93 recordHndl = pdrRepo.getNextRecordHandle(recordHndl); 94 if (recordHndl) 95 { 96 continue; 97 } 98 return PLDM_PLATFORM_INVALID_EFFECTER_ID; 99 } 100 pdr = reinterpret_cast<pldm_state_effecter_pdr*>(pdrEntry.data()); 101 recordHndl = pdr->hdr.record_handle; 102 if (pdr->effecter_id == effecterId) 103 { 104 states = reinterpret_cast<state_effecter_possible_states*>( 105 pdr->possible_states); 106 if (compEffecterCnt > pdr->composite_effecter_count) 107 { 108 log<level::ERR>("The requester sent wrong composite effecter " 109 "count for the effecter", 110 entry("EFFECTER_ID=%d", effecterId), 111 entry("COMP_EFF_CNT=%d", compEffecterCnt)); 112 return PLDM_ERROR_INVALID_DATA; 113 } 114 break; 115 } 116 recordHndl = pdrRepo.getNextRecordHandle(recordHndl); 117 if (!recordHndl) 118 { 119 return PLDM_PLATFORM_INVALID_EFFECTER_ID; 120 } 121 pdr = nullptr; 122 } 123 124 std::map<StateSetId, std::function<int(const std::string& objPath, 125 const uint8_t currState)>> 126 effecterToDbusEntries = { 127 {PLDM_BOOT_PROGRESS_STATE, 128 [&](const std::string& objPath, const uint8_t currState) { 129 auto stateSet = 130 stateNumToDbusProp.find(PLDM_BOOT_PROGRESS_STATE); 131 if (stateSet == stateNumToDbusProp.end()) 132 { 133 log<level::ERR>("Couldn't find D-Bus mapping for " 134 "PLDM_BOOT_PROGRESS_STATE", 135 entry("EFFECTER_ID=%d", effecterId)); 136 return PLDM_ERROR; 137 } 138 auto iter = stateSet->second.find( 139 stateField[currState].effecter_state); 140 if (iter == stateSet->second.end()) 141 { 142 log<level::ERR>( 143 "Invalid state field passed or field not " 144 "found for PLDM_BOOT_PROGRESS_STATE", 145 entry("EFFECTER_ID=%d", effecterId), 146 entry("FIELD=%d", 147 stateField[currState].effecter_state), 148 entry("OBJECT_PATH=%s", objPath.c_str())); 149 return PLDM_ERROR_INVALID_DATA; 150 } 151 auto dbusProp = "OperatingSystemState"; 152 std::variant<std::string> value{ 153 std::get<std::string>(iter->second)}; 154 auto dbusInterface = 155 "xyz.openbmc_project.State.OperatingSystem.Status"; 156 try 157 { 158 dBusIntf.setDbusProperty(objPath.c_str(), dbusProp, 159 dbusInterface, value); 160 } 161 catch (const std::exception& e) 162 { 163 log<level::ERR>("Error setting property", 164 entry("ERROR=%s", e.what()), 165 entry("PROPERTY=%s", dbusProp), 166 entry("INTERFACE=%s", dbusInterface), 167 entry("PATH=%s", objPath.c_str())); 168 return PLDM_ERROR; 169 } 170 return PLDM_SUCCESS; 171 }}}; 172 173 int rc = PLDM_SUCCESS; 174 auto paths = get(effecterId); 175 for (uint8_t currState = 0; currState < compEffecterCnt; ++currState) 176 { 177 std::vector<StateSetNum> allowed{}; 178 // computation is based on table 79 from DSP0248 v1.1.1 179 uint8_t bitfieldIndex = stateField[currState].effecter_state / 8; 180 uint8_t bit = 181 stateField[currState].effecter_state - (8 * bitfieldIndex); 182 if (states->possible_states_size < bitfieldIndex || 183 !(states->states[bitfieldIndex].byte & (1 << bit))) 184 { 185 log<level::ERR>( 186 "Invalid state set value", entry("EFFECTER_ID=%d", effecterId), 187 entry("VALUE=%d", stateField[currState].effecter_state), 188 entry("COMPOSITE_EFFECTER_ID=%d", currState), 189 entry("DBUS_PATH=%c", paths[currState].c_str())); 190 rc = PLDM_PLATFORM_SET_EFFECTER_UNSUPPORTED_SENSORSTATE; 191 break; 192 } 193 auto iter = effecterToDbusEntries.find(states->state_set_id); 194 if (iter == effecterToDbusEntries.end()) 195 { 196 uint16_t setId = states->state_set_id; 197 log<level::ERR>( 198 "Did not find the state set for the state effecter pdr ", 199 entry("STATE=%d", setId), entry("EFFECTER_ID=%d", effecterId)); 200 rc = PLDM_PLATFORM_INVALID_STATE_VALUE; 201 break; 202 } 203 if (stateField[currState].set_request == PLDM_REQUEST_SET) 204 { 205 rc = iter->second(paths[currState], currState); 206 if (rc != PLDM_SUCCESS) 207 { 208 break; 209 } 210 } 211 uint8_t* nextState = 212 reinterpret_cast<uint8_t*>(states) + 213 sizeof(state_effecter_possible_states) - sizeof(states->states) + 214 (states->possible_states_size * sizeof(states->states)); 215 states = reinterpret_cast<state_effecter_possible_states*>(nextState); 216 } 217 return rc; 218 } 219 220 } // namespace responder 221 } // namespace pldm 222