| #include "io.hpp" |
| |
| #include "internal/sys.hpp" |
| |
| #include <fcntl.h> |
| |
| #include <cstdint> |
| #include <cstring> |
| #include <string> |
| |
| namespace host_tool |
| { |
| |
| const std::string DevMemDevice::devMemPath = "/dev/mem"; |
| |
| bool DevMemDevice::read(const std::size_t offset, const std::size_t length, |
| void* const destination) |
| { |
| devMemFd = sys->open(devMemPath.c_str(), O_RDONLY); |
| if (devMemFd < 0) |
| { |
| return false; |
| } |
| |
| /* Map based on aligned addresses - behind the scenes. */ |
| const std::size_t alignedDiff = offset % sys->getpagesize(); |
| const std::size_t alignedOffset = offset - alignedDiff; |
| const std::size_t alignedSize = length + alignedDiff; |
| |
| // addr, length, prot, flags, fd, offset |
| devMemMapped = sys->mmap(0, alignedSize, PROT_READ, MAP_SHARED, devMemFd, |
| alignedOffset); |
| if (devMemMapped == MAP_FAILED) |
| { |
| std::fprintf(stderr, "Failed to mmap at offset: 0x%zx, length: %zu\n", |
| offset, length); |
| sys->close(devMemFd); |
| return false; |
| } |
| |
| void* alignedSource = |
| static_cast<std::uint8_t*>(devMemMapped) + alignedDiff; |
| |
| /* Copy the bytes. */ |
| std::memcpy(destination, alignedSource, length); |
| |
| /* Close the map between reads for now. */ |
| sys->munmap(devMemMapped, length); |
| sys->close(devMemFd); |
| |
| return true; |
| } |
| |
| bool DevMemDevice::write(const std::size_t offset, const std::size_t length, |
| const void* const source) |
| { |
| devMemFd = sys->open(devMemPath.c_str(), O_RDWR); |
| if (devMemFd < 0) |
| { |
| std::fprintf(stderr, "Failed to open /dev/mem for writing\n"); |
| return false; |
| } |
| |
| /* Map based on aligned addresses - behind the scenes. */ |
| const std::size_t alignedDiff = offset % sys->getpagesize(); |
| const std::size_t alignedOffset = offset - alignedDiff; |
| const std::size_t alignedSize = length + alignedDiff; |
| |
| // addr, length, prot, flags, fd, offset |
| devMemMapped = sys->mmap(0, alignedSize, PROT_WRITE, MAP_SHARED, devMemFd, |
| alignedOffset); |
| |
| if (devMemMapped == MAP_FAILED) |
| { |
| std::fprintf(stderr, "Failed to mmap at offset: 0x%zx, length: %zu\n", |
| offset, length); |
| sys->close(devMemFd); |
| return false; |
| } |
| |
| void* alignedDestination = |
| static_cast<std::uint8_t*>(devMemMapped) + alignedDiff; |
| |
| /* Copy the bytes. */ |
| std::memcpy(alignedDestination, source, length); |
| |
| /* Close the map between writes for now. */ |
| sys->munmap(devMemMapped, length); |
| sys->close(devMemFd); |
| |
| return true; |
| } |
| |
| PpcMemDevice::~PpcMemDevice() |
| { |
| // Attempt to close in case reads or writes didn't close themselves |
| close(); |
| } |
| |
| void PpcMemDevice::close() |
| { |
| if (ppcMemFd >= 0) |
| { |
| sys->close(ppcMemFd); |
| ppcMemFd = -1; |
| } |
| } |
| |
| bool PpcMemDevice::read(const std::size_t offset, const std::size_t length, |
| void* const destination) |
| { |
| ppcMemFd = sys->open(ppcMemPath.c_str(), O_RDWR); |
| if (ppcMemFd < 0) |
| { |
| std::fprintf(stderr, "Failed to open PPC LPC access path: %s", |
| ppcMemPath.c_str()); |
| return false; |
| } |
| |
| int ret = sys->pread(ppcMemFd, destination, length, offset); |
| if (ret < 0) |
| { |
| std::fprintf(stderr, "IO read failed at offset: 0x%zx, length: %zu\n", |
| offset, length); |
| close(); |
| return false; |
| } |
| |
| close(); |
| return true; |
| } |
| |
| bool PpcMemDevice::write(const std::size_t offset, const std::size_t length, |
| const void* const source) |
| { |
| ppcMemFd = sys->open(ppcMemPath.c_str(), O_RDWR); |
| if (ppcMemFd < 0) |
| { |
| std::fprintf(stderr, "Failed to open PPC LPC access path: %s", |
| ppcMemPath.c_str()); |
| return false; |
| } |
| |
| ssize_t ret = sys->pwrite(ppcMemFd, source, length, offset); |
| if (ret < 0) |
| { |
| std::fprintf(stderr, "IO write failed at offset: 0x%zx, length: %zu\n", |
| offset, length); |
| close(); |
| return false; |
| } |
| |
| close(); |
| return true; |
| } |
| |
| } // namespace host_tool |