blob: 053cdd35da4b85ac2fa9ef4d2e0422459d994e82 [file] [log] [blame]
/*
* Copyright (c) 2021 Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the License); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an AS IS BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "dev_mem.hpp"
#include <cstddef>
#include <iostream>
#include <fcntl.h>
#include <poll.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
#include <unistd.h>
namespace EthosU {
namespace DevMem {
/****************************************************************************
* Exception
****************************************************************************/
Exception::Exception(const char *msg) : msg(msg) {}
Exception::Exception(const std::string &msg) : msg(msg) {}
Exception::~Exception() throw() {}
const char *Exception::what() const throw() {
return msg.c_str();
}
/****************************************************************************
* DevMem
****************************************************************************/
DevMem::DevMem(uintptr_t address, size_t size) :
base(nullptr), pageMask(sysconf(_SC_PAGESIZE) - 1), pageOffset(address & pageMask), size(size) {
int fd = ::open("/dev/mem", O_RDWR | O_SYNC);
if (fd < 0) {
throw Exception("Failed to open device");
}
base = reinterpret_cast<char *>(
::mmap(nullptr, pageOffset + size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, address & ~pageMask));
if (base == MAP_FAILED) {
throw Exception("MMap failed");
}
::close(fd);
}
DevMem::~DevMem() {
::munmap(base, pageOffset + size);
}
void DevMem::read(char *dst, size_t length, size_t offset) {
if (offset + length > size) {
throw Exception("Read failed");
}
// TODO Why do not std::copy() or memcpy work?
for (size_t i = 0; i < length; i++) {
dst[i] = base[pageOffset + offset + i];
}
}
void DevMem::write(char *src, size_t length, size_t offset) {
if (offset + length > size) {
throw Exception("Write failed");
}
// TODO Why do not std::copy() or memcpy work?
for (size_t i = 0; i < length; i++) {
base[pageOffset + offset + i] = src[i];
}
}
/****************************************************************************
* Log
****************************************************************************/
Log::Log(uintptr_t address, size_t size) : DevMem(address, size) {}
void Log::clear() {
LogHeader header;
read(header, 0);
uint32_t rpos = header.write;
write(rpos, offsetof(LogHeader, read));
}
void Log::print() {
LogHeader header;
read(header, 0);
if (header.size < LOG_SIZE_MIN || header.size > LOG_SIZE_MAX) {
std::string msg = "Incorrect ring buffer values. size=" + std::to_string(header.size) +
", read=" + std::to_string(header.read) + ", write=" + std::to_string(header.write);
throw Exception(msg.c_str());
}
size_t rpos = header.read;
// Skip forward if read is more than 'size' behind
if (rpos + header.size < header.write) {
rpos = header.write - header.size;
}
while (rpos < header.write) {
char c;
size_t offset = rpos++ % header.size + sizeof(header);
read(c, offset);
std::cout << c;
}
}
} // namespace DevMem
} // namespace EthosU