1 #include "bios_table.hpp" 2 3 #include <libpldm/base.h> 4 #include <libpldm/bios_table.h> 5 #include <libpldm/utils.h> 6 7 #include <phosphor-logging/lg2.hpp> 8 9 #include <fstream> 10 11 PHOSPHOR_LOG2_USING; 12 13 namespace pldm 14 { 15 namespace responder 16 { 17 namespace bios 18 { 19 BIOSTable::BIOSTable(const char* filePath) : filePath(filePath) {} 20 21 bool BIOSTable::isEmpty() const noexcept 22 { 23 bool empty = false; 24 try 25 { 26 empty = fs::is_empty(filePath); 27 } 28 catch (const fs::filesystem_error&) 29 { 30 return true; 31 } 32 return empty; 33 } 34 35 void BIOSTable::store(const Table& table) 36 { 37 std::ofstream stream(filePath.string(), std::ios::out | std::ios::binary); 38 stream.write(reinterpret_cast<const char*>(table.data()), table.size()); 39 } 40 41 void BIOSTable::load(Response& response) const 42 { 43 auto currSize = response.size(); 44 auto fileSize = fs::file_size(filePath); 45 response.resize(currSize + fileSize); 46 std::ifstream stream(filePath.string(), std::ios::in | std::ios::binary); 47 stream.read(reinterpret_cast<char*>(response.data() + currSize), fileSize); 48 } 49 50 BIOSStringTable::BIOSStringTable(const Table& stringTable) : 51 stringTable(stringTable) 52 {} 53 54 BIOSStringTable::BIOSStringTable(const BIOSTable& biosTable) 55 { 56 biosTable.load(stringTable); 57 } 58 59 std::string BIOSStringTable::findString(uint16_t handle) const 60 { 61 auto stringEntry = pldm_bios_table_string_find_by_handle( 62 stringTable.data(), stringTable.size(), handle); 63 if (stringEntry == nullptr) 64 { 65 throw std::invalid_argument("Invalid String Handle"); 66 } 67 return table::string::decodeString(stringEntry); 68 } 69 70 uint16_t BIOSStringTable::findHandle(const std::string& name) const 71 { 72 auto stringEntry = pldm_bios_table_string_find_by_string( 73 stringTable.data(), stringTable.size(), name.c_str()); 74 if (stringEntry == nullptr) 75 { 76 throw std::invalid_argument("Invalid String Name"); 77 } 78 79 return table::string::decodeHandle(stringEntry); 80 } 81 82 namespace table 83 { 84 void appendPadAndChecksum(Table& table) 85 { 86 size_t payloadSize = table.size(); 87 table.resize(payloadSize + pldm_bios_table_pad_checksum_size(payloadSize)); 88 // No validation of return value as preconditions are satisfied 89 pldm_bios_table_append_pad_checksum(table.data(), table.size(), 90 &payloadSize); 91 } 92 93 namespace string 94 { 95 uint16_t decodeHandle(const pldm_bios_string_table_entry* entry) 96 { 97 return pldm_bios_table_string_entry_decode_handle(entry); 98 } 99 100 std::string decodeString(const pldm_bios_string_table_entry* entry) 101 { 102 auto strLength = pldm_bios_table_string_entry_decode_string_length(entry); 103 std::vector<char> buffer(strLength + 1 /* sizeof '\0' */); 104 // Preconditions are upheld therefore no error check necessary 105 pldm_bios_table_string_entry_decode_string(entry, buffer.data(), 106 buffer.size()); 107 return std::string(buffer.data(), buffer.data() + strLength); 108 } 109 const pldm_bios_string_table_entry* constructEntry(Table& table, 110 const std::string& str) 111 { 112 auto tableSize = table.size(); 113 auto entryLength = pldm_bios_table_string_entry_encode_length(str.length()); 114 table.resize(tableSize + entryLength); 115 // Preconditions are upheld therefore no error check necessary 116 pldm_bios_table_string_entry_encode(table.data() + tableSize, entryLength, 117 str.c_str(), str.length()); 118 return reinterpret_cast<pldm_bios_string_table_entry*>(table.data() + 119 tableSize); 120 } 121 122 } // namespace string 123 124 namespace attribute 125 { 126 TableHeader decodeHeader(const pldm_bios_attr_table_entry* entry) 127 { 128 auto attrHandle = pldm_bios_table_attr_entry_decode_attribute_handle(entry); 129 auto attrType = pldm_bios_table_attr_entry_decode_attribute_type(entry); 130 auto stringHandle = pldm_bios_table_attr_entry_decode_string_handle(entry); 131 return {attrHandle, attrType, stringHandle}; 132 } 133 134 const pldm_bios_attr_table_entry* findByHandle(const Table& table, 135 uint16_t handle) 136 { 137 return pldm_bios_table_attr_find_by_handle(table.data(), table.size(), 138 handle); 139 } 140 141 const pldm_bios_attr_table_entry* findByStringHandle(const Table& table, 142 uint16_t handle) 143 { 144 return pldm_bios_table_attr_find_by_string_handle(table.data(), 145 table.size(), handle); 146 } 147 148 const pldm_bios_attr_table_entry* 149 constructStringEntry(Table& table, 150 pldm_bios_table_attr_entry_string_info* info) 151 { 152 auto entryLength = 153 pldm_bios_table_attr_entry_string_encode_length(info->def_length); 154 155 auto tableSize = table.size(); 156 table.resize(tableSize + entryLength, 0); 157 int rc = pldm_bios_table_attr_entry_string_encode(table.data() + tableSize, 158 entryLength, info); 159 if (rc != PLDM_SUCCESS) 160 { 161 error("Failed to encode BIOS table string entry, response code '{RC}'", 162 "RC", rc); 163 throw std::runtime_error("Failed to encode BIOS table string entry"); 164 } 165 return reinterpret_cast<pldm_bios_attr_table_entry*>(table.data() + 166 tableSize); 167 } 168 169 const pldm_bios_attr_table_entry* 170 constructIntegerEntry(Table& table, 171 pldm_bios_table_attr_entry_integer_info* info) 172 { 173 auto entryLength = pldm_bios_table_attr_entry_integer_encode_length(); 174 auto tableSize = table.size(); 175 table.resize(tableSize + entryLength, 0); 176 int rc = pldm_bios_table_attr_entry_integer_encode(table.data() + tableSize, 177 entryLength, info); 178 if (rc != PLDM_SUCCESS) 179 { 180 error( 181 "Failed to encode BIOS attribute table integer entry, response code '{RC}'", 182 "RC", rc); 183 throw std::runtime_error( 184 "Failed to encode BIOS attribute table integer entry"); 185 } 186 return reinterpret_cast<pldm_bios_attr_table_entry*>(table.data() + 187 tableSize); 188 } 189 190 StringField decodeStringEntry(const pldm_bios_attr_table_entry* entry) 191 { 192 auto strType = pldm_bios_table_attr_entry_string_decode_string_type(entry); 193 auto minLength = pldm_bios_table_attr_entry_string_decode_min_length(entry); 194 auto maxLength = pldm_bios_table_attr_entry_string_decode_max_length(entry); 195 uint16_t defLength; 196 int rc = pldm_bios_table_attr_entry_string_decode_def_string_length( 197 entry, &defLength); 198 if (rc != PLDM_SUCCESS) 199 { 200 error( 201 "Failed to decode BIOS table string definition length, response code '{RC}'", 202 "RC", rc); 203 throw std::runtime_error( 204 "Failed to decode BIOS table string definitionlength"); 205 } 206 207 std::vector<char> buffer(defLength + 1); 208 pldm_bios_table_attr_entry_string_decode_def_string(entry, buffer.data(), 209 buffer.size()); 210 return {strType, minLength, maxLength, defLength, 211 std::string(buffer.data(), buffer.data() + defLength)}; 212 } 213 214 IntegerField decodeIntegerEntry(const pldm_bios_attr_table_entry* entry) 215 { 216 uint64_t lower, upper, def; 217 uint32_t scalar; 218 219 pldm_bios_table_attr_entry_integer_decode(entry, &lower, &upper, &scalar, 220 &def); 221 return {lower, upper, scalar, def}; 222 } 223 224 const pldm_bios_attr_table_entry* 225 constructEnumEntry(Table& table, pldm_bios_table_attr_entry_enum_info* info) 226 { 227 auto entryLength = pldm_bios_table_attr_entry_enum_encode_length( 228 info->pv_num, info->def_num); 229 230 auto tableSize = table.size(); 231 table.resize(tableSize + entryLength, 0); 232 // Preconditions are upheld therefore no error check necessary 233 pldm_bios_table_attr_entry_enum_encode(table.data() + tableSize, 234 entryLength, info); 235 236 return reinterpret_cast<pldm_bios_attr_table_entry*>(table.data() + 237 tableSize); 238 } 239 240 EnumField decodeEnumEntry(const pldm_bios_attr_table_entry* entry) 241 { 242 uint8_t pvNum; 243 int rc = pldm_bios_table_attr_entry_enum_decode_pv_num(entry, &pvNum); 244 if (rc != PLDM_SUCCESS) 245 { 246 error( 247 "Failed to decode the number of possible values for BIOS table enum entry, response code '{RC}'", 248 "RC", rc); 249 throw std::runtime_error( 250 "Failed to decode the number of possible values for BIOS table enum entry"); 251 } 252 std::vector<uint16_t> pvHdls(pvNum, 0); 253 // Preconditions are upheld therefore no error check necessary 254 pldm_bios_table_attr_entry_enum_decode_pv_hdls(entry, pvHdls.data(), pvNum); 255 // Preconditions are upheld therefore no error check necessary 256 uint8_t defNum; 257 pldm_bios_table_attr_entry_enum_decode_def_num(entry, &defNum); 258 std::vector<uint8_t> defIndices(defNum, 0); 259 pldm_bios_table_attr_entry_enum_decode_def_indices(entry, defIndices.data(), 260 defIndices.size()); 261 return {pvHdls, defIndices}; 262 } 263 264 } // namespace attribute 265 266 namespace attribute_value 267 { 268 TableHeader decodeHeader(const pldm_bios_attr_val_table_entry* entry) 269 { 270 auto handle = 271 pldm_bios_table_attr_value_entry_decode_attribute_handle(entry); 272 auto type = pldm_bios_table_attr_value_entry_decode_attribute_type(entry); 273 return {handle, type}; 274 } 275 276 std::string decodeStringEntry(const pldm_bios_attr_val_table_entry* entry) 277 { 278 variable_field currentString{}; 279 pldm_bios_table_attr_value_entry_string_decode_string(entry, 280 ¤tString); 281 return std::string(currentString.ptr, 282 currentString.ptr + currentString.length); 283 } 284 285 uint64_t decodeIntegerEntry(const pldm_bios_attr_val_table_entry* entry) 286 { 287 return pldm_bios_table_attr_value_entry_integer_decode_cv(entry); 288 } 289 290 std::vector<uint8_t> 291 decodeEnumEntry(const pldm_bios_attr_val_table_entry* entry) 292 { 293 auto number = pldm_bios_table_attr_value_entry_enum_decode_number(entry); 294 std::vector<uint8_t> currHdls(number, 0); 295 pldm_bios_table_attr_value_entry_enum_decode_handles(entry, currHdls.data(), 296 currHdls.size()); 297 return currHdls; 298 } 299 300 const pldm_bios_attr_val_table_entry* 301 constructStringEntry(Table& table, uint16_t attrHandle, uint8_t attrType, 302 const std::string& str) 303 { 304 auto strLen = str.size(); 305 auto entryLength = 306 pldm_bios_table_attr_value_entry_encode_string_length(strLen); 307 auto tableSize = table.size(); 308 table.resize(tableSize + entryLength); 309 int rc = pldm_bios_table_attr_value_entry_encode_string( 310 table.data() + tableSize, entryLength, attrHandle, attrType, strLen, 311 str.c_str()); 312 if (rc != PLDM_SUCCESS) 313 { 314 error( 315 "Failed to encode BIOS attribute table string entry, response code '{RC}'", 316 "RC", rc); 317 throw std::runtime_error( 318 "Failed to encode BIOS attribute table string entry"); 319 } 320 return reinterpret_cast<pldm_bios_attr_val_table_entry*>(table.data() + 321 tableSize); 322 } 323 324 const pldm_bios_attr_val_table_entry* constructIntegerEntry(Table& table, 325 uint16_t attrHandle, 326 uint8_t attrType, 327 uint64_t value) 328 { 329 auto entryLength = pldm_bios_table_attr_value_entry_encode_integer_length(); 330 331 auto tableSize = table.size(); 332 table.resize(tableSize + entryLength); 333 int rc = pldm_bios_table_attr_value_entry_encode_integer( 334 table.data() + tableSize, entryLength, attrHandle, attrType, value); 335 if (rc != PLDM_SUCCESS) 336 { 337 error( 338 "Failed to encode BIOS attribute table integer entry, response code '{RC}'", 339 "RC", rc); 340 throw std::runtime_error( 341 "Failed to encode BIOS attribute table integery entry"); 342 } 343 return reinterpret_cast<pldm_bios_attr_val_table_entry*>(table.data() + 344 tableSize); 345 } 346 347 const pldm_bios_attr_val_table_entry* 348 constructEnumEntry(Table& table, uint16_t attrHandle, uint8_t attrType, 349 const std::vector<uint8_t>& handleIndices) 350 { 351 auto entryLength = pldm_bios_table_attr_value_entry_encode_enum_length( 352 handleIndices.size()); 353 auto tableSize = table.size(); 354 table.resize(tableSize + entryLength); 355 int rc = pldm_bios_table_attr_value_entry_encode_enum( 356 table.data() + tableSize, entryLength, attrHandle, attrType, 357 handleIndices.size(), handleIndices.data()); 358 if (rc != PLDM_SUCCESS) 359 { 360 error( 361 "Failed to encode BIOS attribute table enum entry, response code '{RC}'", 362 "RC", rc); 363 throw std::runtime_error( 364 "Failed to encode BIOS attribute table enum entry"); 365 } 366 return reinterpret_cast<pldm_bios_attr_val_table_entry*>(table.data() + 367 tableSize); 368 } 369 370 std::optional<Table> updateTable(const Table& table, const void* entry, 371 size_t size) 372 { 373 // Replace the old attribute with the new attribute, the size of table will 374 // change: 375 // sizeof(newTableBuffer) = srcTableSize + sizeof(newAttribute) - 376 // sizeof(oldAttribute) + pad(4-byte alignment, max = 377 // 3) 378 // For simplicity, we use 379 // sizeof(newTableBuffer) = srcTableSize + sizeof(newAttribute) + 3 380 size_t destBufferLength = table.size() + size + 3; 381 Table destTable(destBufferLength); 382 383 auto rc = pldm_bios_table_attr_value_copy_and_update( 384 table.data(), table.size(), destTable.data(), &destBufferLength, entry, 385 size); 386 if (rc != PLDM_SUCCESS) 387 { 388 return std::nullopt; 389 } 390 destTable.resize(destBufferLength); 391 392 return destTable; 393 } 394 395 } // namespace attribute_value 396 397 } // namespace table 398 399 } // namespace bios 400 } // namespace responder 401 } // namespace pldm 402