1030b1a8aSPatrick Venture #include "io.hpp"
2030b1a8aSPatrick Venture
3030b1a8aSPatrick Venture #include "internal/sys.hpp"
4030b1a8aSPatrick Venture
5030b1a8aSPatrick Venture #include <fcntl.h>
6030b1a8aSPatrick Venture
7030b1a8aSPatrick Venture #include <cstdint>
8030b1a8aSPatrick Venture #include <cstring>
9030b1a8aSPatrick Venture #include <string>
10030b1a8aSPatrick Venture
11030b1a8aSPatrick Venture namespace host_tool
12030b1a8aSPatrick Venture {
13030b1a8aSPatrick Venture
14030b1a8aSPatrick Venture const std::string DevMemDevice::devMemPath = "/dev/mem";
15030b1a8aSPatrick Venture
read(const std::size_t offset,const std::size_t length,void * const destination)16ac4ff973SPatrick Venture bool DevMemDevice::read(const std::size_t offset, const std::size_t length,
17ac4ff973SPatrick Venture void* const destination)
18ac4ff973SPatrick Venture {
1918bbe3c6SPatrick Venture devMemFd = sys->open(devMemPath.c_str(), O_RDONLY);
20ac4ff973SPatrick Venture if (devMemFd < 0)
21ac4ff973SPatrick Venture {
22ac4ff973SPatrick Venture return false;
23ac4ff973SPatrick Venture }
24ac4ff973SPatrick Venture
25206097b7SPatrick Venture /* Map based on aligned addresses - behind the scenes. */
26206097b7SPatrick Venture const std::size_t alignedDiff = offset % sys->getpagesize();
27206097b7SPatrick Venture const std::size_t alignedOffset = offset - alignedDiff;
28206097b7SPatrick Venture const std::size_t alignedSize = length + alignedDiff;
29206097b7SPatrick Venture
30ac4ff973SPatrick Venture // addr, length, prot, flags, fd, offset
31206097b7SPatrick Venture devMemMapped = sys->mmap(0, alignedSize, PROT_READ, MAP_SHARED, devMemFd,
32206097b7SPatrick Venture alignedOffset);
33ac4ff973SPatrick Venture if (devMemMapped == MAP_FAILED)
34ac4ff973SPatrick Venture {
35213f2db6SPatrick Venture std::fprintf(stderr, "Failed to mmap at offset: 0x%zx, length: %zu\n",
3618bbe3c6SPatrick Venture offset, length);
3718bbe3c6SPatrick Venture sys->close(devMemFd);
3818bbe3c6SPatrick Venture return false;
39ac4ff973SPatrick Venture }
40ac4ff973SPatrick Venture
41*42a44c28SPatrick Williams void* alignedSource =
42*42a44c28SPatrick Williams static_cast<std::uint8_t*>(devMemMapped) + alignedDiff;
43206097b7SPatrick Venture
44ac4ff973SPatrick Venture /* Copy the bytes. */
45206097b7SPatrick Venture std::memcpy(destination, alignedSource, length);
46ac4ff973SPatrick Venture
47ac4ff973SPatrick Venture /* Close the map between reads for now. */
48ac4ff973SPatrick Venture sys->munmap(devMemMapped, length);
4918bbe3c6SPatrick Venture sys->close(devMemFd);
50ac4ff973SPatrick Venture
51ac4ff973SPatrick Venture return true;
52ac4ff973SPatrick Venture }
53ac4ff973SPatrick Venture
write(const std::size_t offset,const std::size_t length,const void * const source)54030b1a8aSPatrick Venture bool DevMemDevice::write(const std::size_t offset, const std::size_t length,
55030b1a8aSPatrick Venture const void* const source)
56030b1a8aSPatrick Venture {
57030b1a8aSPatrick Venture devMemFd = sys->open(devMemPath.c_str(), O_RDWR);
58030b1a8aSPatrick Venture if (devMemFd < 0)
59030b1a8aSPatrick Venture {
6018bbe3c6SPatrick Venture std::fprintf(stderr, "Failed to open /dev/mem for writing\n");
61030b1a8aSPatrick Venture return false;
62030b1a8aSPatrick Venture }
63030b1a8aSPatrick Venture
64206097b7SPatrick Venture /* Map based on aligned addresses - behind the scenes. */
65206097b7SPatrick Venture const std::size_t alignedDiff = offset % sys->getpagesize();
66206097b7SPatrick Venture const std::size_t alignedOffset = offset - alignedDiff;
67206097b7SPatrick Venture const std::size_t alignedSize = length + alignedDiff;
68206097b7SPatrick Venture
69030b1a8aSPatrick Venture // addr, length, prot, flags, fd, offset
70206097b7SPatrick Venture devMemMapped = sys->mmap(0, alignedSize, PROT_WRITE, MAP_SHARED, devMemFd,
71206097b7SPatrick Venture alignedOffset);
72206097b7SPatrick Venture
73030b1a8aSPatrick Venture if (devMemMapped == MAP_FAILED)
74030b1a8aSPatrick Venture {
75213f2db6SPatrick Venture std::fprintf(stderr, "Failed to mmap at offset: 0x%zx, length: %zu\n",
7618bbe3c6SPatrick Venture offset, length);
7718bbe3c6SPatrick Venture sys->close(devMemFd);
7818bbe3c6SPatrick Venture return false;
79030b1a8aSPatrick Venture }
80030b1a8aSPatrick Venture
81*42a44c28SPatrick Williams void* alignedDestination =
82*42a44c28SPatrick Williams static_cast<std::uint8_t*>(devMemMapped) + alignedDiff;
83206097b7SPatrick Venture
84030b1a8aSPatrick Venture /* Copy the bytes. */
85206097b7SPatrick Venture std::memcpy(alignedDestination, source, length);
86030b1a8aSPatrick Venture
87030b1a8aSPatrick Venture /* Close the map between writes for now. */
88030b1a8aSPatrick Venture sys->munmap(devMemMapped, length);
8918bbe3c6SPatrick Venture sys->close(devMemFd);
90030b1a8aSPatrick Venture
91030b1a8aSPatrick Venture return true;
92030b1a8aSPatrick Venture }
93030b1a8aSPatrick Venture
~PpcMemDevice()94286cc6adSBrandon Kim PpcMemDevice::~PpcMemDevice()
95286cc6adSBrandon Kim {
96286cc6adSBrandon Kim // Attempt to close in case reads or writes didn't close themselves
97ea0e470fSPatrick Venture close();
98ea0e470fSPatrick Venture }
99ea0e470fSPatrick Venture
close()100ea0e470fSPatrick Venture void PpcMemDevice::close()
101ea0e470fSPatrick Venture {
102286cc6adSBrandon Kim if (ppcMemFd >= 0)
103286cc6adSBrandon Kim {
104286cc6adSBrandon Kim sys->close(ppcMemFd);
105ea0e470fSPatrick Venture ppcMemFd = -1;
106286cc6adSBrandon Kim }
107286cc6adSBrandon Kim }
108286cc6adSBrandon Kim
read(const std::size_t offset,const std::size_t length,void * const destination)109286cc6adSBrandon Kim bool PpcMemDevice::read(const std::size_t offset, const std::size_t length,
110286cc6adSBrandon Kim void* const destination)
111286cc6adSBrandon Kim {
112286cc6adSBrandon Kim ppcMemFd = sys->open(ppcMemPath.c_str(), O_RDWR);
113286cc6adSBrandon Kim if (ppcMemFd < 0)
114286cc6adSBrandon Kim {
115286cc6adSBrandon Kim std::fprintf(stderr, "Failed to open PPC LPC access path: %s",
116286cc6adSBrandon Kim ppcMemPath.c_str());
117286cc6adSBrandon Kim return false;
118286cc6adSBrandon Kim }
119286cc6adSBrandon Kim
120286cc6adSBrandon Kim int ret = sys->pread(ppcMemFd, destination, length, offset);
121286cc6adSBrandon Kim if (ret < 0)
122286cc6adSBrandon Kim {
123286cc6adSBrandon Kim std::fprintf(stderr, "IO read failed at offset: 0x%zx, length: %zu\n",
124286cc6adSBrandon Kim offset, length);
125ea0e470fSPatrick Venture close();
126286cc6adSBrandon Kim return false;
127286cc6adSBrandon Kim }
128286cc6adSBrandon Kim
129ea0e470fSPatrick Venture close();
130286cc6adSBrandon Kim return true;
131286cc6adSBrandon Kim }
132286cc6adSBrandon Kim
write(const std::size_t offset,const std::size_t length,const void * const source)133286cc6adSBrandon Kim bool PpcMemDevice::write(const std::size_t offset, const std::size_t length,
134286cc6adSBrandon Kim const void* const source)
135286cc6adSBrandon Kim {
136286cc6adSBrandon Kim ppcMemFd = sys->open(ppcMemPath.c_str(), O_RDWR);
137286cc6adSBrandon Kim if (ppcMemFd < 0)
138286cc6adSBrandon Kim {
139286cc6adSBrandon Kim std::fprintf(stderr, "Failed to open PPC LPC access path: %s",
140286cc6adSBrandon Kim ppcMemPath.c_str());
141286cc6adSBrandon Kim return false;
142286cc6adSBrandon Kim }
143286cc6adSBrandon Kim
144286cc6adSBrandon Kim ssize_t ret = sys->pwrite(ppcMemFd, source, length, offset);
145286cc6adSBrandon Kim if (ret < 0)
146286cc6adSBrandon Kim {
147286cc6adSBrandon Kim std::fprintf(stderr, "IO write failed at offset: 0x%zx, length: %zu\n",
148286cc6adSBrandon Kim offset, length);
149ea0e470fSPatrick Venture close();
150286cc6adSBrandon Kim return false;
151286cc6adSBrandon Kim }
152286cc6adSBrandon Kim
153ea0e470fSPatrick Venture close();
154286cc6adSBrandon Kim return true;
155286cc6adSBrandon Kim }
156286cc6adSBrandon Kim
157030b1a8aSPatrick Venture } // namespace host_tool
158