xref: /openbmc/phosphor-ipmi-flash/tools/io.cpp (revision 85e54f1b)
1 #include "io.hpp"
2 
3 #include "internal/sys.hpp"
4 
5 #include <fcntl.h>
6 
7 #include <cstdint>
8 #include <cstring>
9 #include <string>
10 
11 namespace host_tool
12 {
13 
14 const std::string DevMemDevice::devMemPath = "/dev/mem";
15 
16 bool DevMemDevice::read(const std::size_t offset, const std::size_t length,
17                         void* const destination)
18 {
19     devMemFd = sys->open(devMemPath.c_str(), O_RDONLY);
20     if (devMemFd < 0)
21     {
22         return false;
23     }
24 
25     /* Map based on aligned addresses - behind the scenes. */
26     const std::size_t alignedDiff = offset % sys->getpagesize();
27     const std::size_t alignedOffset = offset - alignedDiff;
28     const std::size_t alignedSize = length + alignedDiff;
29 
30     // addr, length, prot, flags, fd, offset
31     devMemMapped = sys->mmap(0, alignedSize, PROT_READ, MAP_SHARED, devMemFd,
32                              alignedOffset);
33     if (devMemMapped == MAP_FAILED)
34     {
35         std::fprintf(stderr, "Failed to mmap at offset: 0x%zx, length: %zu\n",
36                      offset, length);
37         sys->close(devMemFd);
38         return false;
39     }
40 
41     void* alignedSource =
42         static_cast<std::uint8_t*>(devMemMapped) + alignedDiff;
43 
44     /* Copy the bytes. */
45     std::memcpy(destination, alignedSource, length);
46 
47     /* Close the map between reads for now. */
48     sys->munmap(devMemMapped, length);
49     sys->close(devMemFd);
50 
51     return true;
52 }
53 
54 bool DevMemDevice::write(const std::size_t offset, const std::size_t length,
55                          const void* const source)
56 {
57     devMemFd = sys->open(devMemPath.c_str(), O_RDWR);
58     if (devMemFd < 0)
59     {
60         std::fprintf(stderr, "Failed to open /dev/mem for writing\n");
61         return false;
62     }
63 
64     /* Map based on aligned addresses - behind the scenes. */
65     const std::size_t alignedDiff = offset % sys->getpagesize();
66     const std::size_t alignedOffset = offset - alignedDiff;
67     const std::size_t alignedSize = length + alignedDiff;
68 
69     // addr, length, prot, flags, fd, offset
70     devMemMapped = sys->mmap(0, alignedSize, PROT_WRITE, MAP_SHARED, devMemFd,
71                              alignedOffset);
72 
73     if (devMemMapped == MAP_FAILED)
74     {
75         std::fprintf(stderr, "Failed to mmap at offset: 0x%zx, length: %zu\n",
76                      offset, length);
77         sys->close(devMemFd);
78         return false;
79     }
80 
81     void* alignedDestination =
82         static_cast<std::uint8_t*>(devMemMapped) + alignedDiff;
83 
84     /* Copy the bytes. */
85     std::memcpy(alignedDestination, source, length);
86 
87     /* Close the map between writes for now. */
88     sys->munmap(devMemMapped, length);
89     sys->close(devMemFd);
90 
91     return true;
92 }
93 
94 PpcMemDevice::~PpcMemDevice()
95 {
96     // Attempt to close in case reads or writes didn't close themselves
97     close();
98 }
99 
100 void PpcMemDevice::close()
101 {
102     if (ppcMemFd >= 0)
103     {
104         sys->close(ppcMemFd);
105         ppcMemFd = -1;
106     }
107 }
108 
109 bool PpcMemDevice::read(const std::size_t offset, const std::size_t length,
110                         void* const destination)
111 {
112     ppcMemFd = sys->open(ppcMemPath.c_str(), O_RDWR);
113     if (ppcMemFd < 0)
114     {
115         std::fprintf(stderr, "Failed to open PPC LPC access path: %s",
116                      ppcMemPath.c_str());
117         return false;
118     }
119 
120     int ret = sys->pread(ppcMemFd, destination, length, offset);
121     if (ret < 0)
122     {
123         std::fprintf(stderr, "IO read failed at offset: 0x%zx, length: %zu\n",
124                      offset, length);
125         close();
126         return false;
127     }
128 
129     close();
130     return true;
131 }
132 
133 bool PpcMemDevice::write(const std::size_t offset, const std::size_t length,
134                          const void* const source)
135 {
136     ppcMemFd = sys->open(ppcMemPath.c_str(), O_RDWR);
137     if (ppcMemFd < 0)
138     {
139         std::fprintf(stderr, "Failed to open PPC LPC access path: %s",
140                      ppcMemPath.c_str());
141         return false;
142     }
143 
144     ssize_t ret = sys->pwrite(ppcMemFd, source, length, offset);
145     if (ret < 0)
146     {
147         std::fprintf(stderr, "IO write failed at offset: 0x%zx, length: %zu\n",
148                      offset, length);
149         close();
150         return false;
151     }
152 
153     close();
154     return true;
155 }
156 
157 } // namespace host_tool
158