gem5 [DEVELOP-FOR-25.0]
Loading...
Searching...
No Matches
fw_cfg.cc
Go to the documentation of this file.
1/*
2 * Copyright 2022 Google, Inc.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
6 * met: redistributions of source code must retain the above copyright
7 * notice, this list of conditions and the following disclaimer;
8 * redistributions in binary form must reproduce the above copyright
9 * notice, this list of conditions and the following disclaimer in the
10 * documentation and/or other materials provided with the distribution;
11 * neither the name of the copyright holders nor the names of its
12 * contributors may be used to endorse or promote products derived from
13 * this software without specific prior written permission.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
16 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
17 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
18 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
19 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
20 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
21 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
25 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28#include "dev/qemu/fw_cfg.hh"
29
30#include <cstring>
31#include <sstream>
32#include <string>
33
34#include "base/compiler.hh"
35#include "base/cprintf.hh"
36#include "base/logging.hh"
37#include "base/trace.hh"
38#include "debug/QemuFwCfg.hh"
39#include "debug/QemuFwCfgVerbose.hh"
40#include "mem/packet_access.hh"
41#include "sim/byteswap.hh"
42
43namespace gem5
44{
45
46namespace qemu
47{
48
49void
50FwCfgItemFixed::read(void *buf, uint64_t offset, uint32_t to_read)
51{
52 // Get access to the data we need to fill this buffer.
53 const void *data = bytes();
54 const uint64_t total_length = length();
55
56 if (offset > total_length) {
57 // We're completely off the end, so return only zeroes.
58 std::memset(buf, 0, to_read);
59 return;
60 }
61
62 if (offset + to_read > total_length) {
63 // We're partially off the end, truncate this read and zero fill.
64
65 // Figure out how far past the end we're attempting to read.
66 uint64_t overflow = offset + to_read - total_length;
67
68 // Reduce the requested read size to what we can actually fill.
69 to_read -= overflow;
70
71 // Zero out the part we won't read data into.
72 std::memset((uint8_t *)buf + to_read, 0, overflow);
73 }
74
75 // Do the read.
76 std::memcpy(buf, (uint8_t *)data + offset, to_read);
77}
78
79FwCfg::FwCfg(const Params &p, const AddrRangeList &addr_ranges) :
80 PioDevice(p),
81 signature(".[FW_CFG_SIGNATURE]", false, "QEMU CFG", 0),
82 // The ID says we support the traditional interface but not DMA. To enable
83 // DMA, this should be equal to 3.
84 id(".[FW_CFG_ID]", false, "\x1", 1),
85 addrRanges(addr_ranges)
86{
87 // Add the unnamed, fixed items.
89 addItem(&id);
90
91 for (auto factory: p.items) {
92 // Process named items and add them to the index.
93 auto &item = factory->item();
94
95 uint32_t &next_index =
96 item.archSpecific() ? nextArchIndex : nextGenericIndex;
97 const uint32_t &max_index =
98 item.archSpecific() ? MaxArchIndex : MaxGenericIndex;
99
100 // Automatically assign an ID if a fixed one wasn't specified.
101 if (!item.index())
102 item.index(next_index++);
103
104 panic_if(item.index() >= max_index,
105 "Firmware config device out of %s indexes.",
106 item.archSpecific() ? "arch" : "generic");
107
108 addItem(&item);
109 }
110
111 directory.update(names, numbers);
113};
114
115void
117{
118 const auto [kit, ksuccess] =
119 numbers.insert(std::make_pair(item->index(), item));
120
121 panic_if(!ksuccess, "Duplicate firmware config item key %#x, "
122 "paths %s and %s.",
123 item->index(), item->path(), kit->second->path());
124
125 const std::string &path = item->path();
126 if (path.empty() || path[0] != '.') {
127 const auto res =
128 names.insert(std::make_pair(item->path(), item->index()));
129
130 panic_if(!res.second, "Duplicate firmware config item path %s.",
131 item->path());
132 }
133}
134
135void
136FwCfg::select(uint16_t key)
137{
138 DPRINTF(QemuFwCfg, "Selecting item with key %#x.\n", key);
139
140 // Clear any previous selection.
141 offset = 0;
142 current = nullptr;
143
144 auto iter = numbers.find(key);
145 if (iter == numbers.end()) {
146 warn("Firmware config failed to select item with key %#x.", key);
147 return;
148 }
149
150 auto item = iter->second;
151
152 current = item;
153 if (current)
154 DPRINTF(QemuFwCfg, "Selected item with path %s.\n", item->path());
155 else
156 DPRINTF(QemuFwCfg, "No item is currently selected.\n");
157}
158
159void
160FwCfg::readItem(void *buf, uint32_t length)
161{
162 if (!current) {
163 DPRINTF(QemuFwCfgVerbose,
164 "Tried to read while nothing was selected.\n");
165 std::memset(buf, 0, length);
166 return;
167 }
168
169 current->read(buf, offset, length);
170
171 if (gem5::debug::QemuFwCfgVerbose) {
172 std::stringstream data_str;
173 for (int idx = 0; idx < length; idx++)
174 ccprintf(data_str, " %02x", ((uint8_t *)buf)[idx]);
175
176 DPRINTF(QemuFwCfgVerbose, "Read [%#x-%#x) =>%s.\n",
177 offset, offset + length, data_str.str());
178 }
179
180 offset += length;
181}
182
184 FwCfgItemFixed(".[FW_CFG_FILE_DIR]", false, 0x19)
185{}
186
187void
189 const std::map<std::string, uint16_t> &names,
190 const std::map<uint16_t, FwCfgItem *> &numbers)
191{
192 uint32_t count = names.size();
193
194 struct GEM5_PACKED File
195 {
196 uint32_t size;
197 uint16_t select;
198 uint16_t reserved;
199 char name[56];
200 };
201
202 uint64_t bytes = sizeof(count) + sizeof(File) * count;
203 data.resize(bytes);
204
205 uint8_t *ptr = data.data();
206
207 uint32_t be_count = htobe(count);
208 std::memcpy(ptr, &be_count, sizeof(be_count));
209 ptr += sizeof(be_count);
210
211 for (auto &[name, index]: names) {
212 // Fill in the entry.
213 File file{(uint32_t)numbers.at(index)->length(), index, 0, {}};
214 std::memset(file.name, 0, sizeof(file.name));
215 std::strncpy(file.name, name.c_str(), sizeof(file.name) - 1);
216
217 // Fix endianness.
218 file.size = htobe(file.size);
219 file.select = htobe(file.select);
220
221 // Copy it to the buffer and update ptr.
222 std::memcpy(ptr, &file, sizeof(file));
223 ptr += sizeof(file);
224 }
225}
226
228 // This covers both the 16 bit selector, and the 8 bit data reg which
229 // overlaps it.
230 {p.selector_addr, p.selector_addr + 2}}),
231 selectorAddr(p.selector_addr), dataAddr(p.selector_addr + 1)
232{}
233
234Tick
236{
237 const Addr addr = pkt->getAddr();
238 const auto size = pkt->getSize();
239
240 pkt->makeResponse();
241 // The default response is all zeroes.
242 std::memset(pkt->getPtr<uint8_t>(), 0, size);
243
244 if (addr == selectorAddr) {
245 warn("Read from firmware config selector register not supported.");
246 } else if (addr == dataAddr) {
247 if (size == 1) {
248 readItem(pkt->getPtr<void>(), size);
249 } else {
250 warn("Read from firmware config data register with width %d not "
251 "supported.", size);
252 }
253 } else {
254 panic("Unregognized firmware config read [%#x-%#x).",
255 addr, addr + size);
256 }
257
258 return 0;
259}
260
261Tick
263{
264 const Addr addr = pkt->getAddr();
265 const auto size = pkt->getSize();
266
267 pkt->makeResponse();
268
269 if (addr == selectorAddr) {
270 if (size != 2) {
271 warn("Write to firmware config selector register with width %d "
272 "not supported.", size);
273 } else {
274 auto key = pkt->getLE<uint16_t>();
275 select(key);
276 }
277 } else if (addr == dataAddr) {
278 // Writes to the firmware config data can only be done through the
279 // DMA interface.
280 warn("Write to firmware config data register not supported.");
281 } else {
282 panic("Unrecognized firmware config write [%#x-%#x).",
283 addr, addr + size);
284 }
285
286 return 0;
287}
288
290 {p.selector_addr, p.selector_addr + 2},
291 {p.data_addr_range}}),
292 selectorAddr(p.selector_addr),
293 dataAddr(p.data_addr_range.start()), dataSize(p.data_addr_range.size())
294{}
295
296Tick
298{
299 const Addr addr = pkt->getAddr();
300 const auto size = pkt->getSize();
301
302 pkt->makeResponse();
303 // The default response is all zeroes.
304 std::memset(pkt->getPtr<uint8_t>(), 0, size);
305
306 if (addr == selectorAddr) {
307 warn("Read from firmware config selector register not supported.");
308 } else if (addr == dataAddr) {
309 if (size == dataSize) {
310 readItem(pkt->getPtr<void>(), size);
311 } else {
312 warn("Read from firmware config data register with width %d not "
313 "supported.", size);
314 }
315 } else {
316 panic("Unregognized firmware config read [%#x-%#x).",
317 addr, addr + size);
318 }
319
320 return 0;
321}
322
323Tick
325{
326 const Addr addr = pkt->getAddr();
327 const auto size = pkt->getSize();
328
329 pkt->makeResponse();
330
331 if (addr == selectorAddr) {
332 if (size != 2) {
333 warn("Write to firmware config selector register with width %d "
334 "not supported.", size);
335 } else {
336 auto key = pkt->getBE<uint16_t>();
337 select(key);
338 }
339 } else if (addr == dataAddr) {
340 // Writes to the firmware config data can only be done through the
341 // DMA interface.
342 warn("Write to firmware config data register not supported.");
343 } else {
344 panic("Unrecognized firmware config write [%#x-%#x).",
345 addr, addr + size);
346 }
347
348 return 0;
349}
350
351} // namespace qemu
352} // namespace gem5
#define DPRINTF(x,...)
Definition trace.hh:209
const char data[]
virtual std::string name() const
Definition named.hh:60
Addr getAddr() const
Definition packet.hh:807
T getBE() const
Get the data in the packet byte swapped from big endian to host endian.
void makeResponse()
Take a request packet and modify it in place to be suitable for returning as a response to that reque...
Definition packet.hh:1062
T * getPtr()
get a pointer to the data ptr.
Definition packet.hh:1225
unsigned getSize() const
Definition packet.hh:817
T getLE() const
Get the data in the packet byte swapped from little endian to host endian.
PioDevice(const Params &p)
Definition io_device.cc:50
PioDeviceParams Params
Definition io_device.hh:134
static std::stack< std::string > path
Definition serialize.hh:315
const Addr dataAddr
Definition fw_cfg.hh:245
const Addr selectorAddr
Definition fw_cfg.hh:244
Tick read(PacketPtr pkt) override
Pure virtual function that the device must implement.
Definition fw_cfg.cc:235
Tick write(PacketPtr pkt) override
Pure virtual function that the device must implement.
Definition fw_cfg.cc:262
FwCfgIo(const Params &p)
Definition fw_cfg.cc:227
virtual const void * bytes() const =0
void read(void *buf, uint64_t offset, uint32_t to_read) override
Definition fw_cfg.cc:50
virtual uint64_t length() const =0
const std::string & path() const
Definition fw_cfg.hh:74
uint16_t index() const
Definition fw_cfg.hh:71
const Addr selectorAddr
Definition fw_cfg.hh:259
FwCfgMmio(const Params &p)
Definition fw_cfg.cc:289
Tick write(PacketPtr pkt) override
Pure virtual function that the device must implement.
Definition fw_cfg.cc:324
const Addr dataSize
Definition fw_cfg.hh:261
Tick read(PacketPtr pkt) override
Pure virtual function that the device must implement.
Definition fw_cfg.cc:297
const Addr dataAddr
Definition fw_cfg.hh:260
void update(const std::map< std::string, uint16_t > &names, const std::map< uint16_t, FwCfgItem * > &numbers)
Definition fw_cfg.cc:188
const void * bytes() const override
Definition fw_cfg.hh:216
std::vector< uint8_t > data
Definition fw_cfg.hh:208
uint32_t nextArchIndex
Definition fw_cfg.hh:199
Directory directory
Definition fw_cfg.hh:222
FwCfg(const Params &p, const AddrRangeList &addr_ranges)
Definition fw_cfg.cc:79
void readItem(void *buf, uint32_t length)
Definition fw_cfg.cc:160
uint32_t nextGenericIndex
Definition fw_cfg.hh:196
FwCfgItemString id
Definition fw_cfg.hh:221
std::map< uint16_t, FwCfgItem * > numbers
Definition fw_cfg.hh:194
const AddrRangeList addrRanges
Definition fw_cfg.hh:227
static const uint32_t MaxGenericIndex
Definition fw_cfg.hh:197
FwCfgItem * current
Definition fw_cfg.hh:203
static const uint32_t MaxArchIndex
Definition fw_cfg.hh:200
void select(uint16_t key)
Definition fw_cfg.cc:136
FwCfgItemString signature
Definition fw_cfg.hh:220
uint64_t offset
Definition fw_cfg.hh:202
std::map< std::string, uint16_t > names
Definition fw_cfg.hh:193
void addItem(FwCfgItem *item)
Definition fw_cfg.cc:116
std::list< AddrRange > AddrRangeList
Convenience typedef for a collection of address ranges.
Definition addr_range.hh:64
#define panic(...)
This implements a cprintf based panic() function.
Definition logging.hh:220
#define panic_if(cond,...)
Conditional panic macro that checks the supplied condition and only panics if the condition is true a...
Definition logging.hh:246
#define warn(...)
Definition logging.hh:288
Bitfield< 23, 0 > offset
Definition types.hh:144
Bitfield< 0 > p
Bitfield< 62, 54 > reserved
Definition pagetable.hh:66
Bitfield< 3 > addr
Definition types.hh:84
Copyright (c) 2024 Arm Limited All rights reserved.
Definition binary32.hh:36
uint64_t Addr
Address type This will probably be moved somewhere else in the near future.
Definition types.hh:147
uint64_t Tick
Tick count type.
Definition types.hh:58
Packet * PacketPtr
T htobe(T value)
Definition byteswap.hh:174
void ccprintf(cp::Print &print)
Definition cprintf.hh:130
PM4 packets.

Generated on Mon May 26 2025 09:19:10 for gem5 by doxygen 1.13.2