diff options
Diffstat (limited to 'utils/ethosu_logd/main.cpp')
-rw-r--r-- | utils/ethosu_logd/main.cpp | 290 |
1 files changed, 290 insertions, 0 deletions
diff --git a/utils/ethosu_logd/main.cpp b/utils/ethosu_logd/main.cpp new file mode 100644 index 0000000..d7ff1eb --- /dev/null +++ b/utils/ethosu_logd/main.cpp @@ -0,0 +1,290 @@ +/* + * 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 <algorithm> +#include <fstream> +#include <iostream> +#include <memory> +#include <string> +#include <vector> + +#include <dirent.h> + +namespace { + +void help(const char *prog) { + std::cerr << "USAGE: " << prog << " [-h] [--address ADDRESS] [-c] [-C]" << std::endl << std::endl; + std::cerr << "positional argument:" << std::endl; + std::cerr << " -h, --help Show help message and exit" << std::endl; + std::cerr << " --address ADDRESS Address of ring buffer" << std::endl; + std::cerr << " -C Clear the ring buffer" << std::endl; + std::cerr << " -c Read and clear the ring buffer" << std::endl; +} + +class Path { +public: + Path(const std::string path) : path(path) {} + + Path(const char *path) : path(path) {} + + std::string string() const { + return path; + } + + const char *c_str() const { + return path.c_str(); + } + + Path operator/(const std::string &other) const { + if (other.substr(0, 1) == "/") { + return Path(other); + } else { + return Path(path + "/" + other); + } + } + + bool exists() const { + std::ifstream f = std::ifstream(path); + return !!f; + } + + std::vector<Path> find(const std::string &name) const { + std::vector<Path> files; + find(*this, name, files); + return files; + } + + Path parent() const { + return Path(path.substr(0, path.rfind("/"))); + } + +private: + const std::string path; + + static void find(const Path &path, const std::string &name, std::vector<Path> &files) { + DIR *dir = opendir(path.c_str()); + if (dir == nullptr) { + throw EthosU::DevMem::Exception(std::string("Failed to open ") + path.string()); + } + + const dirent *dentry; + while ((dentry = readdir(dir)) != nullptr) { + const std::string dname = dentry->d_name; + const Path pathname = path / dname; + + // Add path to list if it matches 'name' + if (dname == name) { + files.push_back(pathname); + } + + // Call 'find' recursively for directories + if (dname != "." && dname != ".." && dentry->d_type == DT_DIR) { + find(pathname, name, files); + } + } + + closedir(dir); + } +}; + +bool grep(const Path &path, const std::string &match) { + std::ifstream ifs(path.c_str(), std::ios_base::binary); + std::string content = std::string(std::istreambuf_iterator<char>(ifs), std::istreambuf_iterator<char>()); + return content.find(match) != std::string::npos; +} + +class DTS { +public: + DTS(const Path &path) : path(path) {} + + void getRegByName(const std::string &name, uintptr_t &address, size_t &size) const { + size_t index = 0; + for (const auto &n : getString("reg-names")) { + if (n == name) { + getRegByIndex(index, address, size); + return; + } + + index++; + } + + throw EthosU::DevMem::Exception(std::string("Failed to find 'reg-name' ") + name); + } + + void getRegByIndex(const size_t index, uintptr_t &address, size_t &size) const { + size_t addressCell = getAddressCells(); + size_t sizeCell = getSizeCells(); + size_t offset = index * (addressCell + sizeCell) * 4; + + address = getInt("reg", offset, addressCell * 4); + size = getInt("reg", offset + addressCell * 4, sizeCell * 4); + } + +private: + const Path path; + + size_t getAddressCells() const { + const Path p = path / "#address-cells"; + if (!p.exists()) { + return 2; + } + + return getInt(p.string(), 0, 4); + } + + size_t getSizeCells() const { + const Path p = path / "#size-cells"; + if (!p.exists()) { + return 2; + } + + return getInt(p.string(), 0, 4); + } + + std::vector<char> getProperty(const std::string &name) const { + const Path propertyPath = path / name; + std::ifstream ifs(propertyPath.c_str(), std::ios_base::binary); + std::vector<char> content = + std::vector<char>(std::istreambuf_iterator<char>(ifs), std::istreambuf_iterator<char>()); + return content; + } + + std::vector<std::string> getString(const std::string &name) const { + std::vector<char> property = getProperty(name); + std::vector<std::string> names; + + for (std::vector<char>::iterator end, it = property.begin(); + (end = std::find(it, property.end(), '\0')) != property.end(); + it = end + 1) { + names.push_back(std::string(it, end)); + } + + return names; + } + + uint64_t getInt(const std::string &name, const size_t offset, const size_t size) const { + const std::vector<char> property = getProperty(name); + + switch (size) { + case 1: + return toCpu<uint8_t>(&property[offset]); + case 2: + return toCpu<uint16_t>(&property[offset]); + case 4: + return toCpu<uint32_t>(&property[offset]); + case 8: + return toCpu<uint64_t>(&property[offset]); + default: + throw EthosU::DevMem::Exception("Illegal integer size"); + } + } + + static constexpr bool isBigEndian() { + int d = 0x12345678; + return (d & 0xf) == 1; + } + + template <typename T> + static T toCpu(const char *src) { + T dst; + char *d = reinterpret_cast<char *>(&dst); + + if (isBigEndian()) { + for (size_t i = 0; i < sizeof(T); i++) { + d[i] = src[i]; + } + } else { + for (size_t i = 0; i < sizeof(T); i++) { + d[i] = src[sizeof(T) - 1 - i]; + } + } + + return dst; + } +}; + +void getAddressSizeFromDtb(uintptr_t &address, size_t &size) { + // This is the file system path to the device tree + const Path devtree = "/sys/firmware/devicetree/base"; + + // Search device tree for <path>/**/compatible + for (const auto &path : devtree.find("compatible")) { + // Grep for "ethosu" in 'compatible' + if (grep(path, "arm,ethosu")) { + DTS dts(path.parent()); + + dts.getRegByName("print_queue", address, size); + return; + } + } + + throw EthosU::DevMem::Exception("Could not find Ethos-U device tree entry with reg-name 'print_queue'"); +} + +} // namespace + +int main(int argc, char *argv[]) { + try { + uintptr_t address = 0; + size_t size = 0; + bool clearBefore = false; + bool clearAfter = false; + + for (int i = 1; i < argc; i++) { + std::string arg = argv[i]; + + if (arg == "--address") { + address = std::stol(argv[++i], nullptr, 0); + } else if (arg == "-c") { + clearAfter = true; + } else if (arg == "-C") { + clearBefore = true; + } else if (arg == "-h" || arg == "--help") { + help(argv[0]); + ::exit(0); + } else { + std::cerr << "Illegal argument '" + arg + "'" << std::endl; + help(argv[0]); + ::exit(1); + } + } + + if (address == 0) { + getAddressSizeFromDtb(address, size); + } + + EthosU::DevMem::Log log(address, size); + + if (clearBefore) { + log.clear(); + } + + log.print(); + + if (clearAfter) { + log.clear(); + } + } catch (std::exception &e) { + printf("Error: %s\n", e.what()); + return 1; + } + + return 0; +} |