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_check(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_check(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_check( 117 table.data() + tableSize, entryLength, 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_check( 158 table.data() + tableSize, 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_check( 177 table.data() + tableSize, 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_check( 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_check(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_check(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_check(entry, pvHdls.data(), 255 pvNum); 256 // Preconditions are upheld therefore no error check necessary 257 uint8_t defNum; 258 pldm_bios_table_attr_entry_enum_decode_def_num_check(entry, &defNum); 259 std::vector<uint8_t> defIndices(defNum, 0); 260 pldm_bios_table_attr_entry_enum_decode_def_indices(entry, defIndices.data(), 261 defIndices.size()); 262 return {pvHdls, defIndices}; 263 } 264 265 } // namespace attribute 266 267 namespace attribute_value 268 { 269 TableHeader decodeHeader(const pldm_bios_attr_val_table_entry* entry) 270 { 271 auto handle = 272 pldm_bios_table_attr_value_entry_decode_attribute_handle(entry); 273 auto type = pldm_bios_table_attr_value_entry_decode_attribute_type(entry); 274 return {handle, type}; 275 } 276 277 std::string decodeStringEntry(const pldm_bios_attr_val_table_entry* entry) 278 { 279 variable_field currentString{}; 280 pldm_bios_table_attr_value_entry_string_decode_string(entry, 281 ¤tString); 282 return std::string(currentString.ptr, 283 currentString.ptr + currentString.length); 284 } 285 286 uint64_t decodeIntegerEntry(const pldm_bios_attr_val_table_entry* entry) 287 { 288 return pldm_bios_table_attr_value_entry_integer_decode_cv(entry); 289 } 290 291 std::vector<uint8_t> 292 decodeEnumEntry(const pldm_bios_attr_val_table_entry* entry) 293 { 294 auto number = pldm_bios_table_attr_value_entry_enum_decode_number(entry); 295 std::vector<uint8_t> currHdls(number, 0); 296 pldm_bios_table_attr_value_entry_enum_decode_handles(entry, currHdls.data(), 297 currHdls.size()); 298 return currHdls; 299 } 300 301 const pldm_bios_attr_val_table_entry* 302 constructStringEntry(Table& table, uint16_t attrHandle, uint8_t attrType, 303 const std::string& str) 304 { 305 auto strLen = str.size(); 306 auto entryLength = 307 pldm_bios_table_attr_value_entry_encode_string_length(strLen); 308 auto tableSize = table.size(); 309 table.resize(tableSize + entryLength); 310 int rc = pldm_bios_table_attr_value_entry_encode_string_check( 311 table.data() + tableSize, entryLength, attrHandle, attrType, strLen, 312 str.c_str()); 313 if (rc != PLDM_SUCCESS) 314 { 315 error( 316 "Failed to encode BIOS attribute table string entry, response code '{RC}'", 317 "RC", rc); 318 throw std::runtime_error( 319 "Failed to encode BIOS attribute table string entry"); 320 } 321 return reinterpret_cast<pldm_bios_attr_val_table_entry*>(table.data() + 322 tableSize); 323 } 324 325 const pldm_bios_attr_val_table_entry* constructIntegerEntry(Table& table, 326 uint16_t attrHandle, 327 uint8_t attrType, 328 uint64_t value) 329 { 330 auto entryLength = pldm_bios_table_attr_value_entry_encode_integer_length(); 331 332 auto tableSize = table.size(); 333 table.resize(tableSize + entryLength); 334 int rc = pldm_bios_table_attr_value_entry_encode_integer_check( 335 table.data() + tableSize, entryLength, attrHandle, attrType, value); 336 if (rc != PLDM_SUCCESS) 337 { 338 error( 339 "Failed to encode BIOS attribute table integer entry, response code '{RC}'", 340 "RC", rc); 341 throw std::runtime_error( 342 "Failed to encode BIOS attribute table integery entry"); 343 } 344 return reinterpret_cast<pldm_bios_attr_val_table_entry*>(table.data() + 345 tableSize); 346 } 347 348 const pldm_bios_attr_val_table_entry* 349 constructEnumEntry(Table& table, uint16_t attrHandle, uint8_t attrType, 350 const std::vector<uint8_t>& handleIndices) 351 { 352 auto entryLength = pldm_bios_table_attr_value_entry_encode_enum_length( 353 handleIndices.size()); 354 auto tableSize = table.size(); 355 table.resize(tableSize + entryLength); 356 int rc = pldm_bios_table_attr_value_entry_encode_enum_check( 357 table.data() + tableSize, entryLength, attrHandle, attrType, 358 handleIndices.size(), handleIndices.data()); 359 if (rc != PLDM_SUCCESS) 360 { 361 error( 362 "Failed to encode BIOS attribute table enum entry, response code '{RC}'", 363 "RC", rc); 364 throw std::runtime_error( 365 "Failed to encode BIOS attribute table enum entry"); 366 } 367 return reinterpret_cast<pldm_bios_attr_val_table_entry*>(table.data() + 368 tableSize); 369 } 370 371 std::optional<Table> updateTable(const Table& table, const void* entry, 372 size_t size) 373 { 374 // Replace the old attribute with the new attribute, the size of table will 375 // change: 376 // sizeof(newTableBuffer) = srcTableSize + sizeof(newAttribute) - 377 // sizeof(oldAttribute) + pad(4-byte alignment, max = 378 // 3) 379 // For simplicity, we use 380 // sizeof(newTableBuffer) = srcTableSize + sizeof(newAttribute) + 3 381 size_t destBufferLength = table.size() + size + 3; 382 Table destTable(destBufferLength); 383 384 auto rc = pldm_bios_table_attr_value_copy_and_update( 385 table.data(), table.size(), destTable.data(), &destBufferLength, entry, 386 size); 387 if (rc != PLDM_SUCCESS) 388 { 389 return std::nullopt; 390 } 391 destTable.resize(destBufferLength); 392 393 return destTable; 394 } 395 396 } // namespace attribute_value 397 398 } // namespace table 399 400 } // namespace bios 401 } // namespace responder 402 } // namespace pldm 403