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