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 auto sizeWithoutPad = table.size(); 85 auto padAndChecksumSize = pldm_bios_table_pad_checksum_size(sizeWithoutPad); 86 table.resize(table.size() + padAndChecksumSize); 87 88 pldm_bios_table_append_pad_checksum(table.data(), table.size(), 89 sizeWithoutPad); 90 } 91 92 namespace string 93 { 94 uint16_t decodeHandle(const pldm_bios_string_table_entry* entry) 95 { 96 return pldm_bios_table_string_entry_decode_handle(entry); 97 } 98 99 std::string decodeString(const pldm_bios_string_table_entry* entry) 100 { 101 auto strLength = pldm_bios_table_string_entry_decode_string_length(entry); 102 std::vector<char> buffer(strLength + 1 /* sizeof '\0' */); 103 // Preconditions are upheld therefore no error check necessary 104 pldm_bios_table_string_entry_decode_string_check(entry, buffer.data(), 105 buffer.size()); 106 return std::string(buffer.data(), buffer.data() + strLength); 107 } 108 const pldm_bios_string_table_entry* constructEntry(Table& table, 109 const std::string& str) 110 { 111 auto tableSize = table.size(); 112 auto entryLength = pldm_bios_table_string_entry_encode_length(str.length()); 113 table.resize(tableSize + entryLength); 114 // Preconditions are upheld therefore no error check necessary 115 pldm_bios_table_string_entry_encode_check( 116 table.data() + tableSize, entryLength, str.c_str(), str.length()); 117 return reinterpret_cast<pldm_bios_string_table_entry*>(table.data() + 118 tableSize); 119 } 120 121 } // namespace string 122 123 namespace attribute 124 { 125 TableHeader decodeHeader(const pldm_bios_attr_table_entry* entry) 126 { 127 auto attrHandle = pldm_bios_table_attr_entry_decode_attribute_handle(entry); 128 auto attrType = pldm_bios_table_attr_entry_decode_attribute_type(entry); 129 auto stringHandle = pldm_bios_table_attr_entry_decode_string_handle(entry); 130 return {attrHandle, attrType, stringHandle}; 131 } 132 133 const pldm_bios_attr_table_entry* findByHandle(const Table& table, 134 uint16_t handle) 135 { 136 return pldm_bios_table_attr_find_by_handle(table.data(), table.size(), 137 handle); 138 } 139 140 const pldm_bios_attr_table_entry* findByStringHandle(const Table& table, 141 uint16_t handle) 142 { 143 return pldm_bios_table_attr_find_by_string_handle(table.data(), 144 table.size(), handle); 145 } 146 147 const pldm_bios_attr_table_entry* 148 constructStringEntry(Table& table, 149 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_check( 157 table.data() + tableSize, entryLength, info); 158 if (rc != PLDM_SUCCESS) 159 { 160 lg2::error("Failed to encode BIOS table string entry: {LIBPLDM_ERROR}", 161 "LIBPLDM_ERROR", rc); 162 throw std::runtime_error("Failed to encode BIOS table string entry"); 163 } 164 return reinterpret_cast<pldm_bios_attr_table_entry*>(table.data() + 165 tableSize); 166 } 167 168 const pldm_bios_attr_table_entry* 169 constructIntegerEntry(Table& table, 170 pldm_bios_table_attr_entry_integer_info* info) 171 { 172 auto entryLength = pldm_bios_table_attr_entry_integer_encode_length(); 173 auto tableSize = table.size(); 174 table.resize(tableSize + entryLength, 0); 175 int rc = pldm_bios_table_attr_entry_integer_encode_check( 176 table.data() + tableSize, entryLength, info); 177 if (rc != PLDM_SUCCESS) 178 { 179 lg2::error( 180 "Failed to encode BIOS attribute table integer entry: {LIBPLDM_ERROR}", 181 "LIBPLDM_ERROR", rc); 182 throw std::runtime_error( 183 "Failed to encode BIOS attribute table integer entry"); 184 } 185 return reinterpret_cast<pldm_bios_attr_table_entry*>(table.data() + 186 tableSize); 187 } 188 189 StringField decodeStringEntry(const pldm_bios_attr_table_entry* entry) 190 { 191 auto strType = pldm_bios_table_attr_entry_string_decode_string_type(entry); 192 auto minLength = pldm_bios_table_attr_entry_string_decode_min_length(entry); 193 auto maxLength = pldm_bios_table_attr_entry_string_decode_max_length(entry); 194 uint16_t defLength; 195 int rc = pldm_bios_table_attr_entry_string_decode_def_string_length_check( 196 entry, &defLength); 197 if (rc != PLDM_SUCCESS) 198 { 199 lg2::error( 200 "Failed to decode BIOS table string definition length: {LIBPLDM_ERROR}", 201 "LIBPLDM_ERROR", rc); 202 throw std::runtime_error( 203 "Failed to decode BIOS table string definitionlength"); 204 } 205 206 std::vector<char> buffer(defLength + 1); 207 pldm_bios_table_attr_entry_string_decode_def_string(entry, buffer.data(), 208 buffer.size()); 209 return {strType, minLength, maxLength, defLength, 210 std::string(buffer.data(), buffer.data() + defLength)}; 211 } 212 213 IntegerField decodeIntegerEntry(const pldm_bios_attr_table_entry* entry) 214 { 215 uint64_t lower, upper, def; 216 uint32_t scalar; 217 218 pldm_bios_table_attr_entry_integer_decode(entry, &lower, &upper, &scalar, 219 &def); 220 return {lower, upper, scalar, def}; 221 } 222 223 const pldm_bios_attr_table_entry* 224 constructEnumEntry(Table& table, pldm_bios_table_attr_entry_enum_info* info) 225 { 226 auto entryLength = pldm_bios_table_attr_entry_enum_encode_length( 227 info->pv_num, info->def_num); 228 229 auto tableSize = table.size(); 230 table.resize(tableSize + entryLength, 0); 231 // Preconditions are upheld therefore no error check necessary 232 pldm_bios_table_attr_entry_enum_encode_check(table.data() + tableSize, 233 entryLength, info); 234 235 return reinterpret_cast<pldm_bios_attr_table_entry*>(table.data() + 236 tableSize); 237 } 238 239 EnumField decodeEnumEntry(const pldm_bios_attr_table_entry* entry) 240 { 241 uint8_t pvNum; 242 int rc = pldm_bios_table_attr_entry_enum_decode_pv_num_check(entry, &pvNum); 243 if (rc != PLDM_SUCCESS) 244 { 245 lg2::error( 246 "Failed to decode the number of possible values for BIOS table enum entry: {LIBPLDM_ERROR}", 247 "LIBPLDM_ERROR", rc); 248 throw std::runtime_error( 249 "Failed to decode the number of possible values for BIOS table enum entry"); 250 } 251 std::vector<uint16_t> pvHdls(pvNum, 0); 252 // Preconditions are upheld therefore no error check necessary 253 pldm_bios_table_attr_entry_enum_decode_pv_hdls_check(entry, pvHdls.data(), 254 pvNum); 255 // Preconditions are upheld therefore no error check necessary 256 uint8_t defNum; 257 pldm_bios_table_attr_entry_enum_decode_def_num_check(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_check( 310 table.data() + tableSize, entryLength, attrHandle, attrType, strLen, 311 str.c_str()); 312 if (rc != PLDM_SUCCESS) 313 { 314 lg2::error( 315 "Failed to encode BIOS attribute table string entry: {LIBPLDM_ERROR}", 316 "LIBPLDM_ERROR", 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 pldm_bios_table_attr_value_entry_encode_integer( 334 table.data() + tableSize, entryLength, attrHandle, attrType, value); 335 return reinterpret_cast<pldm_bios_attr_val_table_entry*>(table.data() + 336 tableSize); 337 } 338 339 const pldm_bios_attr_val_table_entry* 340 constructEnumEntry(Table& table, uint16_t attrHandle, uint8_t attrType, 341 const std::vector<uint8_t>& handleIndices) 342 { 343 auto entryLength = pldm_bios_table_attr_value_entry_encode_enum_length( 344 handleIndices.size()); 345 auto tableSize = table.size(); 346 table.resize(tableSize + entryLength); 347 int rc = pldm_bios_table_attr_value_entry_encode_enum_check( 348 table.data() + tableSize, entryLength, attrHandle, attrType, 349 handleIndices.size(), handleIndices.data()); 350 if (rc != PLDM_SUCCESS) 351 { 352 lg2::error( 353 "Failed to encode BIOS attribute table enum entry: {LIBPLDM_ERROR}", 354 "LIBPLDM_ERROR", rc); 355 throw std::runtime_error( 356 "Failed to encode BIOS attribute table enum entry"); 357 } 358 return reinterpret_cast<pldm_bios_attr_val_table_entry*>(table.data() + 359 tableSize); 360 } 361 362 std::optional<Table> updateTable(const Table& table, const void* entry, 363 size_t size) 364 { 365 // Replace the old attribute with the new attribute, the size of table will 366 // change: 367 // sizeof(newTableBuffer) = srcTableSize + sizeof(newAttribute) - 368 // sizeof(oldAttribute) + pad(4-byte alignment, max = 369 // 3) 370 // For simplicity, we use 371 // sizeof(newTableBuffer) = srcTableSize + sizeof(newAttribute) + 3 372 size_t destBufferLength = table.size() + size + 3; 373 Table destTable(destBufferLength); 374 375 auto rc = pldm_bios_table_attr_value_copy_and_update( 376 table.data(), table.size(), destTable.data(), &destBufferLength, entry, 377 size); 378 if (rc != PLDM_SUCCESS) 379 { 380 return std::nullopt; 381 } 382 destTable.resize(destBufferLength); 383 384 return destTable; 385 } 386 387 } // namespace attribute_value 388 389 } // namespace table 390 391 } // namespace bios 392 } // namespace responder 393 } // namespace pldm 394