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 {PLDM_SYSTEM_POWER_STATE, 76 {{PLDM_OFF_SOFT_GRACEFUL, 77 "xyz.openbmc_project.State.Chassis.Transition.Off"s}}}}; 78 using namespace phosphor::logging; 79 using namespace pldm::responder::pdr; 80 using namespace pldm::responder::effecter::dbus_mapping; 81 82 state_effecter_possible_states* states = nullptr; 83 pldm_state_effecter_pdr* pdr = nullptr; 84 uint8_t compEffecterCnt = stateField.size(); 85 uint32_t recordHndl{}; 86 Repo& pdrRepo = get(PDR_JSONS_DIR); 87 pdr::Entry pdrEntry{}; 88 89 while (!pdr) 90 { 91 pdrEntry = pdrRepo.at(recordHndl); 92 pldm_pdr_hdr* header = reinterpret_cast<pldm_pdr_hdr*>(pdrEntry.data()); 93 if (header->type != PLDM_STATE_EFFECTER_PDR) 94 { 95 recordHndl = pdrRepo.getNextRecordHandle(recordHndl); 96 if (recordHndl) 97 { 98 continue; 99 } 100 return PLDM_PLATFORM_INVALID_EFFECTER_ID; 101 } 102 pdr = reinterpret_cast<pldm_state_effecter_pdr*>(pdrEntry.data()); 103 recordHndl = pdr->hdr.record_handle; 104 if (pdr->effecter_id == effecterId) 105 { 106 states = reinterpret_cast<state_effecter_possible_states*>( 107 pdr->possible_states); 108 if (compEffecterCnt > pdr->composite_effecter_count) 109 { 110 log<level::ERR>("The requester sent wrong composite effecter " 111 "count for the effecter", 112 entry("EFFECTER_ID=%d", effecterId), 113 entry("COMP_EFF_CNT=%d", compEffecterCnt)); 114 return PLDM_ERROR_INVALID_DATA; 115 } 116 break; 117 } 118 recordHndl = pdrRepo.getNextRecordHandle(recordHndl); 119 if (!recordHndl) 120 { 121 return PLDM_PLATFORM_INVALID_EFFECTER_ID; 122 } 123 pdr = nullptr; 124 } 125 126 std::map<StateSetId, std::function<int(const std::string& objPath, 127 const uint8_t currState)>> 128 effecterToDbusEntries = { 129 {PLDM_BOOT_PROGRESS_STATE, 130 [&](const std::string& objPath, const uint8_t currState) { 131 auto stateSet = 132 stateNumToDbusProp.find(PLDM_BOOT_PROGRESS_STATE); 133 if (stateSet == stateNumToDbusProp.end()) 134 { 135 log<level::ERR>("Couldn't find D-Bus mapping for " 136 "PLDM_BOOT_PROGRESS_STATE", 137 entry("EFFECTER_ID=%d", effecterId)); 138 return PLDM_ERROR; 139 } 140 auto iter = stateSet->second.find( 141 stateField[currState].effecter_state); 142 if (iter == stateSet->second.end()) 143 { 144 log<level::ERR>( 145 "Invalid state field passed or field not " 146 "found for PLDM_BOOT_PROGRESS_STATE", 147 entry("EFFECTER_ID=%d", effecterId), 148 entry("FIELD=%d", 149 stateField[currState].effecter_state), 150 entry("OBJECT_PATH=%s", objPath.c_str())); 151 return PLDM_ERROR_INVALID_DATA; 152 } 153 auto dbusProp = "OperatingSystemState"; 154 std::variant<std::string> value{ 155 std::get<std::string>(iter->second)}; 156 auto dbusInterface = 157 "xyz.openbmc_project.State.OperatingSystem.Status"; 158 try 159 { 160 dBusIntf.setDbusProperty(objPath.c_str(), dbusProp, 161 dbusInterface, value); 162 } 163 catch (const std::exception& e) 164 { 165 log<level::ERR>("Error setting property", 166 entry("ERROR=%s", e.what()), 167 entry("PROPERTY=%s", dbusProp), 168 entry("INTERFACE=%s", dbusInterface), 169 entry("PATH=%s", objPath.c_str())); 170 return PLDM_ERROR; 171 } 172 return PLDM_SUCCESS; 173 }}, 174 {PLDM_SYSTEM_POWER_STATE, 175 [&](const std::string& objPath, const uint8_t currState) { 176 auto stateSet = 177 stateNumToDbusProp.find(PLDM_SYSTEM_POWER_STATE); 178 if (stateSet == stateNumToDbusProp.end()) 179 { 180 log<level::ERR>("Couldn't find D-Bus mapping for " 181 "PLDM_SYSTEM_POWER_STATE", 182 entry("EFFECTER_ID=%d", effecterId)); 183 return PLDM_ERROR; 184 } 185 auto iter = stateSet->second.find( 186 stateField[currState].effecter_state); 187 if (iter == stateSet->second.end()) 188 { 189 log<level::ERR>( 190 "Invalid state field passed or field not " 191 "found for PLDM_SYSTEM_POWER_STATE", 192 entry("EFFECTER_ID=%d", effecterId), 193 entry("FIELD=%d", 194 stateField[currState].effecter_state), 195 entry("OBJECT_PATH=%s", objPath.c_str())); 196 return PLDM_ERROR_INVALID_DATA; 197 } 198 auto dbusProp = "RequestedPowerTransition"; 199 std::variant<std::string> value{ 200 std::get<std::string>(iter->second)}; 201 auto dbusInterface = "xyz.openbmc_project.State.Chassis"; 202 try 203 { 204 dBusIntf.setDbusProperty(objPath.c_str(), dbusProp, 205 dbusInterface, value); 206 } 207 catch (const std::exception& e) 208 { 209 log<level::ERR>("Error setting property", 210 entry("ERROR=%s", e.what()), 211 entry("PROPERTY=%s", dbusProp), 212 entry("INTERFACE=%s", dbusInterface), 213 entry("PATH=%s", objPath.c_str())); 214 return PLDM_ERROR; 215 } 216 return PLDM_SUCCESS; 217 }}}; 218 219 int rc = PLDM_SUCCESS; 220 auto paths = get(effecterId); 221 for (uint8_t currState = 0; currState < compEffecterCnt; ++currState) 222 { 223 std::vector<StateSetNum> allowed{}; 224 // computation is based on table 79 from DSP0248 v1.1.1 225 uint8_t bitfieldIndex = stateField[currState].effecter_state / 8; 226 uint8_t bit = 227 stateField[currState].effecter_state - (8 * bitfieldIndex); 228 if (states->possible_states_size < bitfieldIndex || 229 !(states->states[bitfieldIndex].byte & (1 << bit))) 230 { 231 log<level::ERR>( 232 "Invalid state set value", entry("EFFECTER_ID=%d", effecterId), 233 entry("VALUE=%d", stateField[currState].effecter_state), 234 entry("COMPOSITE_EFFECTER_ID=%d", currState), 235 entry("DBUS_PATH=%c", paths[currState].c_str())); 236 rc = PLDM_PLATFORM_SET_EFFECTER_UNSUPPORTED_SENSORSTATE; 237 break; 238 } 239 auto iter = effecterToDbusEntries.find(states->state_set_id); 240 if (iter == effecterToDbusEntries.end()) 241 { 242 uint16_t setId = states->state_set_id; 243 log<level::ERR>( 244 "Did not find the state set for the state effecter pdr ", 245 entry("STATE=%d", setId), entry("EFFECTER_ID=%d", effecterId)); 246 rc = PLDM_PLATFORM_INVALID_STATE_VALUE; 247 break; 248 } 249 if (stateField[currState].set_request == PLDM_REQUEST_SET) 250 { 251 rc = iter->second(paths[currState], currState); 252 if (rc != PLDM_SUCCESS) 253 { 254 break; 255 } 256 } 257 uint8_t* nextState = 258 reinterpret_cast<uint8_t*>(states) + 259 sizeof(state_effecter_possible_states) - sizeof(states->states) + 260 (states->possible_states_size * sizeof(states->states)); 261 states = reinterpret_cast<state_effecter_possible_states*>(nextState); 262 } 263 return rc; 264 } 265 266 } // namespace responder 267 } // namespace pldm 268