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* 110 constructEntry(Table& table, 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*>( 119 table.data() + 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* 135 findByHandle(const Table& table, 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* 142 findByStringHandle(const Table& table, 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* constructStringEntry( 149 Table& table, pldm_bios_table_attr_entry_string_info* info) 150 { 151 auto entryLength = 152 pldm_bios_table_attr_entry_string_encode_length(info->def_length); 153 154 auto tableSize = table.size(); 155 table.resize(tableSize + entryLength, 0); 156 int rc = pldm_bios_table_attr_entry_string_encode(table.data() + tableSize, 157 entryLength, info); 158 if (rc != PLDM_SUCCESS) 159 { 160 error("Failed to encode BIOS table string entry, response code '{RC}'", 161 "RC", rc); 162 throw std::runtime_error("Failed to encode BIOS table string entry"); 163 } 164 return reinterpret_cast<pldm_bios_attr_table_entry*>( 165 table.data() + tableSize); 166 } 167 168 const pldm_bios_attr_table_entry* constructIntegerEntry( 169 Table& table, pldm_bios_table_attr_entry_integer_info* info) 170 { 171 auto entryLength = pldm_bios_table_attr_entry_integer_encode_length(); 172 auto tableSize = table.size(); 173 table.resize(tableSize + entryLength, 0); 174 int rc = pldm_bios_table_attr_entry_integer_encode(table.data() + tableSize, 175 entryLength, info); 176 if (rc != PLDM_SUCCESS) 177 { 178 error( 179 "Failed to encode BIOS attribute table integer entry, response code '{RC}'", 180 "RC", rc); 181 throw std::runtime_error( 182 "Failed to encode BIOS attribute table integer entry"); 183 } 184 return reinterpret_cast<pldm_bios_attr_table_entry*>( 185 table.data() + tableSize); 186 } 187 188 StringField decodeStringEntry(const pldm_bios_attr_table_entry* entry) 189 { 190 auto strType = pldm_bios_table_attr_entry_string_decode_string_type(entry); 191 auto minLength = pldm_bios_table_attr_entry_string_decode_min_length(entry); 192 auto maxLength = pldm_bios_table_attr_entry_string_decode_max_length(entry); 193 uint16_t defLength; 194 int rc = pldm_bios_table_attr_entry_string_decode_def_string_length( 195 entry, &defLength); 196 if (rc != PLDM_SUCCESS) 197 { 198 error( 199 "Failed to decode BIOS table string definition length, response code '{RC}'", 200 "RC", rc); 201 throw std::runtime_error( 202 "Failed to decode BIOS table string definitionlength"); 203 } 204 205 std::vector<char> buffer(defLength + 1); 206 pldm_bios_table_attr_entry_string_decode_def_string(entry, buffer.data(), 207 buffer.size()); 208 return {strType, minLength, maxLength, defLength, 209 std::string(buffer.data(), buffer.data() + defLength)}; 210 } 211 212 IntegerField decodeIntegerEntry(const pldm_bios_attr_table_entry* entry) 213 { 214 uint64_t lower, upper, def; 215 uint32_t scalar; 216 217 pldm_bios_table_attr_entry_integer_decode(entry, &lower, &upper, &scalar, 218 &def); 219 return {lower, upper, scalar, def}; 220 } 221 222 const pldm_bios_attr_table_entry* 223 constructEnumEntry(Table& table, pldm_bios_table_attr_entry_enum_info* info) 224 { 225 auto entryLength = pldm_bios_table_attr_entry_enum_encode_length( 226 info->pv_num, info->def_num); 227 228 auto tableSize = table.size(); 229 table.resize(tableSize + entryLength, 0); 230 // Preconditions are upheld therefore no error check necessary 231 pldm_bios_table_attr_entry_enum_encode(table.data() + tableSize, 232 entryLength, info); 233 234 return reinterpret_cast<pldm_bios_attr_table_entry*>( 235 table.data() + tableSize); 236 } 237 238 EnumField decodeEnumEntry(const pldm_bios_attr_table_entry* entry) 239 { 240 uint8_t pvNum; 241 int rc = pldm_bios_table_attr_entry_enum_decode_pv_num(entry, &pvNum); 242 if (rc != PLDM_SUCCESS) 243 { 244 error( 245 "Failed to decode the number of possible values for BIOS table enum entry, response code '{RC}'", 246 "RC", rc); 247 throw std::runtime_error( 248 "Failed to decode the number of possible values for BIOS table enum entry"); 249 } 250 std::vector<uint16_t> pvHdls(pvNum, 0); 251 // Preconditions are upheld therefore no error check necessary 252 pldm_bios_table_attr_entry_enum_decode_pv_hdls(entry, pvHdls.data(), pvNum); 253 // Preconditions are upheld therefore no error check necessary 254 uint8_t defNum; 255 pldm_bios_table_attr_entry_enum_decode_def_num(entry, &defNum); 256 std::vector<uint8_t> defIndices(defNum, 0); 257 pldm_bios_table_attr_entry_enum_decode_def_indices(entry, defIndices.data(), 258 defIndices.size()); 259 return {pvHdls, defIndices}; 260 } 261 262 } // namespace attribute 263 264 namespace attribute_value 265 { 266 TableHeader decodeHeader(const pldm_bios_attr_val_table_entry* entry) 267 { 268 auto handle = 269 pldm_bios_table_attr_value_entry_decode_attribute_handle(entry); 270 auto type = pldm_bios_table_attr_value_entry_decode_attribute_type(entry); 271 return {handle, type}; 272 } 273 274 std::string decodeStringEntry(const pldm_bios_attr_val_table_entry* entry) 275 { 276 variable_field currentString{}; 277 pldm_bios_table_attr_value_entry_string_decode_string( 278 entry, ¤tString); 279 return std::string(currentString.ptr, 280 currentString.ptr + currentString.length); 281 } 282 283 uint64_t decodeIntegerEntry(const pldm_bios_attr_val_table_entry* entry) 284 { 285 return pldm_bios_table_attr_value_entry_integer_decode_cv(entry); 286 } 287 288 std::vector<uint8_t> 289 decodeEnumEntry(const pldm_bios_attr_val_table_entry* entry) 290 { 291 auto number = pldm_bios_table_attr_value_entry_enum_decode_number(entry); 292 std::vector<uint8_t> currHdls(number, 0); 293 pldm_bios_table_attr_value_entry_enum_decode_handles(entry, currHdls.data(), 294 currHdls.size()); 295 return currHdls; 296 } 297 298 const pldm_bios_attr_val_table_entry* constructStringEntry( 299 Table& table, uint16_t attrHandle, uint8_t attrType, const std::string& str) 300 { 301 auto strLen = str.size(); 302 auto entryLength = 303 pldm_bios_table_attr_value_entry_encode_string_length(strLen); 304 auto tableSize = table.size(); 305 table.resize(tableSize + entryLength); 306 int rc = pldm_bios_table_attr_value_entry_encode_string( 307 table.data() + tableSize, entryLength, attrHandle, attrType, strLen, 308 str.c_str()); 309 if (rc != PLDM_SUCCESS) 310 { 311 error( 312 "Failed to encode BIOS attribute table string entry, response code '{RC}'", 313 "RC", rc); 314 throw std::runtime_error( 315 "Failed to encode BIOS attribute table string entry"); 316 } 317 return reinterpret_cast<pldm_bios_attr_val_table_entry*>( 318 table.data() + tableSize); 319 } 320 321 const pldm_bios_attr_val_table_entry* constructIntegerEntry( 322 Table& table, uint16_t attrHandle, uint8_t attrType, uint64_t value) 323 { 324 auto entryLength = pldm_bios_table_attr_value_entry_encode_integer_length(); 325 326 auto tableSize = table.size(); 327 table.resize(tableSize + entryLength); 328 int rc = pldm_bios_table_attr_value_entry_encode_integer( 329 table.data() + tableSize, entryLength, attrHandle, attrType, value); 330 if (rc != PLDM_SUCCESS) 331 { 332 error( 333 "Failed to encode BIOS attribute table integer entry, response code '{RC}'", 334 "RC", rc); 335 throw std::runtime_error( 336 "Failed to encode BIOS attribute table integery entry"); 337 } 338 return reinterpret_cast<pldm_bios_attr_val_table_entry*>( 339 table.data() + tableSize); 340 } 341 342 const pldm_bios_attr_val_table_entry* 343 constructEnumEntry(Table& table, uint16_t attrHandle, uint8_t attrType, 344 const std::vector<uint8_t>& handleIndices) 345 { 346 auto entryLength = pldm_bios_table_attr_value_entry_encode_enum_length( 347 handleIndices.size()); 348 auto tableSize = table.size(); 349 table.resize(tableSize + entryLength); 350 int rc = pldm_bios_table_attr_value_entry_encode_enum( 351 table.data() + tableSize, entryLength, attrHandle, attrType, 352 handleIndices.size(), handleIndices.data()); 353 if (rc != PLDM_SUCCESS) 354 { 355 error( 356 "Failed to encode BIOS attribute table enum entry, response code '{RC}'", 357 "RC", rc); 358 throw std::runtime_error( 359 "Failed to encode BIOS attribute table enum entry"); 360 } 361 return reinterpret_cast<pldm_bios_attr_val_table_entry*>( 362 table.data() + tableSize); 363 } 364 365 std::optional<Table> updateTable(const Table& table, const void* entry, 366 size_t size) 367 { 368 // Replace the old attribute with the new attribute, the size of table will 369 // change: 370 // sizeof(newTableBuffer) = srcTableSize + sizeof(newAttribute) - 371 // sizeof(oldAttribute) + pad(4-byte alignment, max = 372 // 3) 373 // For simplicity, we use 374 // sizeof(newTableBuffer) = srcTableSize + sizeof(newAttribute) + 3 375 size_t destBufferLength = table.size() + size + 3; 376 Table destTable(destBufferLength); 377 378 auto rc = pldm_bios_table_attr_value_copy_and_update( 379 table.data(), table.size(), destTable.data(), &destBufferLength, entry, 380 size); 381 if (rc != PLDM_SUCCESS) 382 { 383 return std::nullopt; 384 } 385 destTable.resize(destBufferLength); 386 387 return destTable; 388 } 389 390 } // namespace attribute_value 391 392 } // namespace table 393 394 } // namespace bios 395 } // namespace responder 396 } // namespace pldm 397