1 #include "pattern.hpp" 2 3 #include "erase.hpp" 4 5 #include <unistd.h> 6 7 #include <phosphor-logging/lg2.hpp> 8 #include <stdplus/fd/create.hpp> 9 #include <stdplus/fd/managed.hpp> 10 #include <xyz/openbmc_project/Common/error.hpp> 11 12 #include <array> 13 #include <iostream> 14 #include <random> 15 #include <span> 16 #include <string> 17 18 namespace estoraged 19 { 20 21 constexpr uint32_t seed = 0x6a656272; 22 constexpr size_t blockSize = 4096; 23 constexpr size_t blockSizeUsing32 = blockSize / sizeof(uint32_t); 24 25 using sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure; 26 using stdplus::fd::ManagedFd; 27 28 void Pattern::writePattern(const uint64_t driveSize) 29 { 30 // static seed defines a fixed prng sequnce so it can be verified later, 31 // and validated for entropy 32 uint64_t currentIndex = 0; 33 34 // random number generator seeded with a constant value will 35 // generate a predictable sequence of values NOLINTNEXTLINE 36 std::minstd_rand0 generator(seed); 37 std::array<std::byte, blockSize> randArr{}; 38 39 ManagedFd fd = 40 stdplus::fd::open(devPath, stdplus::fd::OpenAccess::WriteOnly); 41 42 while (currentIndex < driveSize) 43 { 44 // generate a 4k block of prng 45 std::array<uint32_t, blockSizeUsing32>* randArrFill = 46 reinterpret_cast<std::array<uint32_t, blockSizeUsing32>*>(&randArr); 47 for (uint32_t i = 0; i < blockSizeUsing32; i++) 48 { 49 (*randArrFill)[i] = generator(); 50 } 51 // if we can write all 4k bytes do that, else write the remainder 52 size_t writeSize = currentIndex + blockSize < driveSize 53 ? blockSize 54 : driveSize - currentIndex; 55 if (fd.write({randArr.data(), writeSize}).size() != writeSize) 56 { 57 lg2::error("Estoraged erase pattern unable to write sizeof(long)", 58 "REDFISH_MESSAGE_ID", 59 std::string("eStorageD.1.0.EraseFailure"), 60 "REDFISH_MESSAGE_ARGS", std::to_string(fd.get())); 61 throw InternalFailure(); 62 } 63 currentIndex = currentIndex + writeSize; 64 } 65 } 66 67 void Pattern::verifyPattern(const uint64_t driveSize) 68 { 69 70 uint64_t currentIndex = 0; 71 // random number generator seeded with a constant value will 72 // generate a predictable sequence of values NOLINTNEXTLINE 73 std::minstd_rand0 generator(seed); 74 std::array<std::byte, blockSize> randArr{}; 75 std::array<std::byte, blockSize> readArr{}; 76 77 ManagedFd fd = 78 stdplus::fd::open(devPath, stdplus::fd::OpenAccess::ReadOnly); 79 80 while (currentIndex < driveSize) 81 { 82 size_t readSize = currentIndex + blockSize < driveSize 83 ? blockSize 84 : driveSize - currentIndex; 85 try 86 { 87 std::array<uint32_t, blockSizeUsing32>* randArrFill = 88 reinterpret_cast<std::array<uint32_t, blockSizeUsing32>*>( 89 &randArr); 90 for (uint32_t i = 0; i < blockSizeUsing32; i++) 91 { 92 (*randArrFill)[i] = generator(); 93 } 94 fd.read({readArr.data(), readSize}); 95 } 96 catch (...) 97 { 98 lg2::error("Estoraged erase pattern unable to read", 99 "REDFISH_MESSAGE_ID", 100 std::string("eStorageD.1.0.EraseFailure"), 101 "REDFISH_MESSAGE_ARGS", std::to_string(fd.get())); 102 throw InternalFailure(); 103 } 104 105 if (!std::equal(randArr.begin(), randArr.begin() + readSize, 106 readArr.begin(), readArr.begin() + readSize)) 107 { 108 lg2::error("Estoraged erase pattern does not match", 109 "REDFISH_MESSAGE_ID", 110 std::string("eStorageD.1.0.EraseFailure")); 111 throw InternalFailure(); 112 } 113 currentIndex = currentIndex + readSize; 114 } 115 } 116 117 } // namespace estoraged 118