blob: d7ff1ebff84915c83d9a21d4c2aba35e66e73430 [file] [log] [blame]
Kristofer Jonsson6d80c422021-10-14 10:09:08 +02001/*
2 * Copyright (c) 2021 Arm Limited. All rights reserved.
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 *
6 * Licensed under the Apache License, Version 2.0 (the License); you may
7 * not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
9 *
10 * www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an AS IS BASIS, WITHOUT
14 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
17 */
18
19#include "dev_mem.hpp"
20
21#include <algorithm>
22#include <fstream>
23#include <iostream>
24#include <memory>
25#include <string>
26#include <vector>
27
28#include <dirent.h>
29
30namespace {
31
32void help(const char *prog) {
33 std::cerr << "USAGE: " << prog << " [-h] [--address ADDRESS] [-c] [-C]" << std::endl << std::endl;
34 std::cerr << "positional argument:" << std::endl;
35 std::cerr << " -h, --help Show help message and exit" << std::endl;
36 std::cerr << " --address ADDRESS Address of ring buffer" << std::endl;
37 std::cerr << " -C Clear the ring buffer" << std::endl;
38 std::cerr << " -c Read and clear the ring buffer" << std::endl;
39}
40
41class Path {
42public:
43 Path(const std::string path) : path(path) {}
44
45 Path(const char *path) : path(path) {}
46
47 std::string string() const {
48 return path;
49 }
50
51 const char *c_str() const {
52 return path.c_str();
53 }
54
55 Path operator/(const std::string &other) const {
56 if (other.substr(0, 1) == "/") {
57 return Path(other);
58 } else {
59 return Path(path + "/" + other);
60 }
61 }
62
63 bool exists() const {
64 std::ifstream f = std::ifstream(path);
65 return !!f;
66 }
67
68 std::vector<Path> find(const std::string &name) const {
69 std::vector<Path> files;
70 find(*this, name, files);
71 return files;
72 }
73
74 Path parent() const {
75 return Path(path.substr(0, path.rfind("/")));
76 }
77
78private:
79 const std::string path;
80
81 static void find(const Path &path, const std::string &name, std::vector<Path> &files) {
82 DIR *dir = opendir(path.c_str());
83 if (dir == nullptr) {
84 throw EthosU::DevMem::Exception(std::string("Failed to open ") + path.string());
85 }
86
87 const dirent *dentry;
88 while ((dentry = readdir(dir)) != nullptr) {
89 const std::string dname = dentry->d_name;
90 const Path pathname = path / dname;
91
92 // Add path to list if it matches 'name'
93 if (dname == name) {
94 files.push_back(pathname);
95 }
96
97 // Call 'find' recursively for directories
98 if (dname != "." && dname != ".." && dentry->d_type == DT_DIR) {
99 find(pathname, name, files);
100 }
101 }
102
103 closedir(dir);
104 }
105};
106
107bool grep(const Path &path, const std::string &match) {
108 std::ifstream ifs(path.c_str(), std::ios_base::binary);
109 std::string content = std::string(std::istreambuf_iterator<char>(ifs), std::istreambuf_iterator<char>());
110 return content.find(match) != std::string::npos;
111}
112
113class DTS {
114public:
115 DTS(const Path &path) : path(path) {}
116
117 void getRegByName(const std::string &name, uintptr_t &address, size_t &size) const {
118 size_t index = 0;
119 for (const auto &n : getString("reg-names")) {
120 if (n == name) {
121 getRegByIndex(index, address, size);
122 return;
123 }
124
125 index++;
126 }
127
128 throw EthosU::DevMem::Exception(std::string("Failed to find 'reg-name' ") + name);
129 }
130
131 void getRegByIndex(const size_t index, uintptr_t &address, size_t &size) const {
132 size_t addressCell = getAddressCells();
133 size_t sizeCell = getSizeCells();
134 size_t offset = index * (addressCell + sizeCell) * 4;
135
136 address = getInt("reg", offset, addressCell * 4);
137 size = getInt("reg", offset + addressCell * 4, sizeCell * 4);
138 }
139
140private:
141 const Path path;
142
143 size_t getAddressCells() const {
144 const Path p = path / "#address-cells";
145 if (!p.exists()) {
146 return 2;
147 }
148
149 return getInt(p.string(), 0, 4);
150 }
151
152 size_t getSizeCells() const {
153 const Path p = path / "#size-cells";
154 if (!p.exists()) {
155 return 2;
156 }
157
158 return getInt(p.string(), 0, 4);
159 }
160
161 std::vector<char> getProperty(const std::string &name) const {
162 const Path propertyPath = path / name;
163 std::ifstream ifs(propertyPath.c_str(), std::ios_base::binary);
164 std::vector<char> content =
165 std::vector<char>(std::istreambuf_iterator<char>(ifs), std::istreambuf_iterator<char>());
166 return content;
167 }
168
169 std::vector<std::string> getString(const std::string &name) const {
170 std::vector<char> property = getProperty(name);
171 std::vector<std::string> names;
172
173 for (std::vector<char>::iterator end, it = property.begin();
174 (end = std::find(it, property.end(), '\0')) != property.end();
175 it = end + 1) {
176 names.push_back(std::string(it, end));
177 }
178
179 return names;
180 }
181
182 uint64_t getInt(const std::string &name, const size_t offset, const size_t size) const {
183 const std::vector<char> property = getProperty(name);
184
185 switch (size) {
186 case 1:
187 return toCpu<uint8_t>(&property[offset]);
188 case 2:
189 return toCpu<uint16_t>(&property[offset]);
190 case 4:
191 return toCpu<uint32_t>(&property[offset]);
192 case 8:
193 return toCpu<uint64_t>(&property[offset]);
194 default:
195 throw EthosU::DevMem::Exception("Illegal integer size");
196 }
197 }
198
199 static constexpr bool isBigEndian() {
200 int d = 0x12345678;
201 return (d & 0xf) == 1;
202 }
203
204 template <typename T>
205 static T toCpu(const char *src) {
206 T dst;
207 char *d = reinterpret_cast<char *>(&dst);
208
209 if (isBigEndian()) {
210 for (size_t i = 0; i < sizeof(T); i++) {
211 d[i] = src[i];
212 }
213 } else {
214 for (size_t i = 0; i < sizeof(T); i++) {
215 d[i] = src[sizeof(T) - 1 - i];
216 }
217 }
218
219 return dst;
220 }
221};
222
223void getAddressSizeFromDtb(uintptr_t &address, size_t &size) {
224 // This is the file system path to the device tree
225 const Path devtree = "/sys/firmware/devicetree/base";
226
227 // Search device tree for <path>/**/compatible
228 for (const auto &path : devtree.find("compatible")) {
229 // Grep for "ethosu" in 'compatible'
230 if (grep(path, "arm,ethosu")) {
231 DTS dts(path.parent());
232
233 dts.getRegByName("print_queue", address, size);
234 return;
235 }
236 }
237
238 throw EthosU::DevMem::Exception("Could not find Ethos-U device tree entry with reg-name 'print_queue'");
239}
240
241} // namespace
242
243int main(int argc, char *argv[]) {
244 try {
245 uintptr_t address = 0;
246 size_t size = 0;
247 bool clearBefore = false;
248 bool clearAfter = false;
249
250 for (int i = 1; i < argc; i++) {
251 std::string arg = argv[i];
252
253 if (arg == "--address") {
254 address = std::stol(argv[++i], nullptr, 0);
255 } else if (arg == "-c") {
256 clearAfter = true;
257 } else if (arg == "-C") {
258 clearBefore = true;
259 } else if (arg == "-h" || arg == "--help") {
260 help(argv[0]);
261 ::exit(0);
262 } else {
263 std::cerr << "Illegal argument '" + arg + "'" << std::endl;
264 help(argv[0]);
265 ::exit(1);
266 }
267 }
268
269 if (address == 0) {
270 getAddressSizeFromDtb(address, size);
271 }
272
273 EthosU::DevMem::Log log(address, size);
274
275 if (clearBefore) {
276 log.clear();
277 }
278
279 log.print();
280
281 if (clearAfter) {
282 log.clear();
283 }
284 } catch (std::exception &e) {
285 printf("Error: %s\n", e.what());
286 return 1;
287 }
288
289 return 0;
290}