xref: /openbmc/estoraged/src/erase/pattern.cpp (revision 67a47446)
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