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 namespace pldm 12 { 13 namespace responder 14 { 15 namespace bios 16 { 17 BIOSTable::BIOSTable(const char* filePath) : filePath(filePath) {} 18 19 bool BIOSTable::isEmpty() const noexcept 20 { 21 bool empty = false; 22 try 23 { 24 empty = fs::is_empty(filePath); 25 } 26 catch (const fs::filesystem_error& e) 27 { 28 return true; 29 } 30 return empty; 31 } 32 33 void BIOSTable::store(const Table& table) 34 { 35 std::ofstream stream(filePath.string(), std::ios::out | std::ios::binary); 36 stream.write(reinterpret_cast<const char*>(table.data()), table.size()); 37 } 38 39 void BIOSTable::load(Response& response) const 40 { 41 auto currSize = response.size(); 42 auto fileSize = fs::file_size(filePath); 43 response.resize(currSize + fileSize); 44 std::ifstream stream(filePath.string(), std::ios::in | std::ios::binary); 45 stream.read(reinterpret_cast<char*>(response.data() + currSize), fileSize); 46 } 47 48 BIOSStringTable::BIOSStringTable(const Table& stringTable) : 49 stringTable(stringTable) 50 {} 51 52 BIOSStringTable::BIOSStringTable(const BIOSTable& biosTable) 53 { 54 biosTable.load(stringTable); 55 } 56 57 std::string BIOSStringTable::findString(uint16_t handle) const 58 { 59 auto stringEntry = pldm_bios_table_string_find_by_handle( 60 stringTable.data(), stringTable.size(), handle); 61 if (stringEntry == nullptr) 62 { 63 throw std::invalid_argument("Invalid String Handle"); 64 } 65 return table::string::decodeString(stringEntry); 66 } 67 68 uint16_t BIOSStringTable::findHandle(const std::string& name) const 69 { 70 auto stringEntry = pldm_bios_table_string_find_by_string( 71 stringTable.data(), stringTable.size(), name.c_str()); 72 if (stringEntry == nullptr) 73 { 74 throw std::invalid_argument("Invalid String Name"); 75 } 76 77 return table::string::decodeHandle(stringEntry); 78 } 79 80 namespace table 81 { 82 void appendPadAndChecksum(Table& table) 83 { 84 size_t payloadSize = table.size(); 85 table.resize(payloadSize + pldm_bios_table_pad_checksum_size(payloadSize)); 86 // No validation of return value as preconditions are satisfied 87 pldm_bios_table_append_pad_checksum_check(table.data(), table.size(), 88 &payloadSize); 89 } 90 91 namespace string 92 { 93 uint16_t decodeHandle(const pldm_bios_string_table_entry* entry) 94 { 95 return pldm_bios_table_string_entry_decode_handle(entry); 96 } 97 98 std::string decodeString(const pldm_bios_string_table_entry* entry) 99 { 100 auto strLength = pldm_bios_table_string_entry_decode_string_length(entry); 101 std::vector<char> buffer(strLength + 1 /* sizeof '\0' */); 102 // Preconditions are upheld therefore no error check necessary 103 pldm_bios_table_string_entry_decode_string_check(entry, buffer.data(), 104 buffer.size()); 105 return std::string(buffer.data(), buffer.data() + strLength); 106 } 107 const pldm_bios_string_table_entry* constructEntry(Table& table, 108 const std::string& str) 109 { 110 auto tableSize = table.size(); 111 auto entryLength = pldm_bios_table_string_entry_encode_length(str.length()); 112 table.resize(tableSize + entryLength); 113 // Preconditions are upheld therefore no error check necessary 114 pldm_bios_table_string_entry_encode_check( 115 table.data() + tableSize, entryLength, str.c_str(), str.length()); 116 return reinterpret_cast<pldm_bios_string_table_entry*>(table.data() + 117 tableSize); 118 } 119 120 } // namespace string 121 122 namespace attribute 123 { 124 TableHeader decodeHeader(const pldm_bios_attr_table_entry* entry) 125 { 126 auto attrHandle = pldm_bios_table_attr_entry_decode_attribute_handle(entry); 127 auto attrType = pldm_bios_table_attr_entry_decode_attribute_type(entry); 128 auto stringHandle = pldm_bios_table_attr_entry_decode_string_handle(entry); 129 return {attrHandle, attrType, stringHandle}; 130 } 131 132 const pldm_bios_attr_table_entry* findByHandle(const Table& table, 133 uint16_t handle) 134 { 135 return pldm_bios_table_attr_find_by_handle(table.data(), table.size(), 136 handle); 137 } 138 139 const pldm_bios_attr_table_entry* findByStringHandle(const Table& table, 140 uint16_t handle) 141 { 142 return pldm_bios_table_attr_find_by_string_handle(table.data(), 143 table.size(), handle); 144 } 145 146 const pldm_bios_attr_table_entry* 147 constructStringEntry(Table& table, 148 pldm_bios_table_attr_entry_string_info* info) 149 { 150 auto entryLength = 151 pldm_bios_table_attr_entry_string_encode_length(info->def_length); 152 153 auto tableSize = table.size(); 154 table.resize(tableSize + entryLength, 0); 155 int rc = pldm_bios_table_attr_entry_string_encode_check( 156 table.data() + tableSize, entryLength, info); 157 if (rc != PLDM_SUCCESS) 158 { 159 lg2::error("Failed to encode BIOS table string entry: {LIBPLDM_ERROR}", 160 "LIBPLDM_ERROR", rc); 161 throw std::runtime_error("Failed to encode BIOS table string entry"); 162 } 163 return reinterpret_cast<pldm_bios_attr_table_entry*>(table.data() + 164 tableSize); 165 } 166 167 const pldm_bios_attr_table_entry* 168 constructIntegerEntry(Table& table, 169 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_check( 175 table.data() + tableSize, entryLength, info); 176 if (rc != PLDM_SUCCESS) 177 { 178 lg2::error( 179 "Failed to encode BIOS attribute table integer entry: {LIBPLDM_ERROR}", 180 "LIBPLDM_ERROR", 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*>(table.data() + 185 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_check( 195 entry, &defLength); 196 if (rc != PLDM_SUCCESS) 197 { 198 lg2::error( 199 "Failed to decode BIOS table string definition length: {LIBPLDM_ERROR}", 200 "LIBPLDM_ERROR", 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_check(table.data() + tableSize, 232 entryLength, info); 233 234 return reinterpret_cast<pldm_bios_attr_table_entry*>(table.data() + 235 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_check(entry, &pvNum); 242 if (rc != PLDM_SUCCESS) 243 { 244 lg2::error( 245 "Failed to decode the number of possible values for BIOS table enum entry: {LIBPLDM_ERROR}", 246 "LIBPLDM_ERROR", 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_check(entry, pvHdls.data(), 253 pvNum); 254 // Preconditions are upheld therefore no error check necessary 255 uint8_t defNum; 256 pldm_bios_table_attr_entry_enum_decode_def_num_check(entry, &defNum); 257 std::vector<uint8_t> defIndices(defNum, 0); 258 pldm_bios_table_attr_entry_enum_decode_def_indices(entry, defIndices.data(), 259 defIndices.size()); 260 return {pvHdls, defIndices}; 261 } 262 263 } // namespace attribute 264 265 namespace attribute_value 266 { 267 TableHeader decodeHeader(const pldm_bios_attr_val_table_entry* entry) 268 { 269 auto handle = 270 pldm_bios_table_attr_value_entry_decode_attribute_handle(entry); 271 auto type = pldm_bios_table_attr_value_entry_decode_attribute_type(entry); 272 return {handle, type}; 273 } 274 275 std::string decodeStringEntry(const pldm_bios_attr_val_table_entry* entry) 276 { 277 variable_field currentString{}; 278 pldm_bios_table_attr_value_entry_string_decode_string(entry, 279 ¤tString); 280 return std::string(currentString.ptr, 281 currentString.ptr + currentString.length); 282 } 283 284 uint64_t decodeIntegerEntry(const pldm_bios_attr_val_table_entry* entry) 285 { 286 return pldm_bios_table_attr_value_entry_integer_decode_cv(entry); 287 } 288 289 std::vector<uint8_t> 290 decodeEnumEntry(const pldm_bios_attr_val_table_entry* entry) 291 { 292 auto number = pldm_bios_table_attr_value_entry_enum_decode_number(entry); 293 std::vector<uint8_t> currHdls(number, 0); 294 pldm_bios_table_attr_value_entry_enum_decode_handles(entry, currHdls.data(), 295 currHdls.size()); 296 return currHdls; 297 } 298 299 const pldm_bios_attr_val_table_entry* 300 constructStringEntry(Table& table, uint16_t attrHandle, uint8_t attrType, 301 const std::string& str) 302 { 303 auto strLen = str.size(); 304 auto entryLength = 305 pldm_bios_table_attr_value_entry_encode_string_length(strLen); 306 auto tableSize = table.size(); 307 table.resize(tableSize + entryLength); 308 int rc = pldm_bios_table_attr_value_entry_encode_string_check( 309 table.data() + tableSize, entryLength, attrHandle, attrType, strLen, 310 str.c_str()); 311 if (rc != PLDM_SUCCESS) 312 { 313 lg2::error( 314 "Failed to encode BIOS attribute table string entry: {LIBPLDM_ERROR}", 315 "LIBPLDM_ERROR", rc); 316 throw std::runtime_error( 317 "Failed to encode BIOS attribute table string entry"); 318 } 319 return reinterpret_cast<pldm_bios_attr_val_table_entry*>(table.data() + 320 tableSize); 321 } 322 323 const pldm_bios_attr_val_table_entry* constructIntegerEntry(Table& table, 324 uint16_t attrHandle, 325 uint8_t attrType, 326 uint64_t value) 327 { 328 auto entryLength = pldm_bios_table_attr_value_entry_encode_integer_length(); 329 330 auto tableSize = table.size(); 331 table.resize(tableSize + entryLength); 332 pldm_bios_table_attr_value_entry_encode_integer( 333 table.data() + tableSize, entryLength, attrHandle, attrType, value); 334 return reinterpret_cast<pldm_bios_attr_val_table_entry*>(table.data() + 335 tableSize); 336 } 337 338 const pldm_bios_attr_val_table_entry* 339 constructEnumEntry(Table& table, uint16_t attrHandle, uint8_t attrType, 340 const std::vector<uint8_t>& handleIndices) 341 { 342 auto entryLength = pldm_bios_table_attr_value_entry_encode_enum_length( 343 handleIndices.size()); 344 auto tableSize = table.size(); 345 table.resize(tableSize + entryLength); 346 int rc = pldm_bios_table_attr_value_entry_encode_enum_check( 347 table.data() + tableSize, entryLength, attrHandle, attrType, 348 handleIndices.size(), handleIndices.data()); 349 if (rc != PLDM_SUCCESS) 350 { 351 lg2::error( 352 "Failed to encode BIOS attribute table enum entry: {LIBPLDM_ERROR}", 353 "LIBPLDM_ERROR", rc); 354 throw std::runtime_error( 355 "Failed to encode BIOS attribute table enum entry"); 356 } 357 return reinterpret_cast<pldm_bios_attr_val_table_entry*>(table.data() + 358 tableSize); 359 } 360 361 std::optional<Table> updateTable(const Table& table, const void* entry, 362 size_t size) 363 { 364 // Replace the old attribute with the new attribute, the size of table will 365 // change: 366 // sizeof(newTableBuffer) = srcTableSize + sizeof(newAttribute) - 367 // sizeof(oldAttribute) + pad(4-byte alignment, max = 368 // 3) 369 // For simplicity, we use 370 // sizeof(newTableBuffer) = srcTableSize + sizeof(newAttribute) + 3 371 size_t destBufferLength = table.size() + size + 3; 372 Table destTable(destBufferLength); 373 374 auto rc = pldm_bios_table_attr_value_copy_and_update( 375 table.data(), table.size(), destTable.data(), &destBufferLength, entry, 376 size); 377 if (rc != PLDM_SUCCESS) 378 { 379 return std::nullopt; 380 } 381 destTable.resize(destBufferLength); 382 383 return destTable; 384 } 385 386 } // namespace attribute_value 387 388 } // namespace table 389 390 } // namespace bios 391 } // namespace responder 392 } // namespace pldm 393