gem5 v24.0.0.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
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:210
const char data[]
virtual std::string name() const
Definition named.hh:47
A Packet is used to encapsulate a transfer between two objects in the memory system (e....
Definition packet.hh:295
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.
This device is the base class which all devices senstive to an address range inherit from.
Definition io_device.hh:103
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 void read(void *buf, uint64_t offset, uint32_t to_read)=0
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
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
std::map< uint16_t, FwCfgItem * > numbers
Definition fw_cfg.hh:194
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
#define panic(...)
This implements a cprintf based panic() function.
Definition logging.hh:188
#define panic_if(cond,...)
Conditional panic macro that checks the supplied condition and only panics if the condition is true a...
Definition logging.hh:214
#define warn(...)
Definition logging.hh:256
Bitfield< 23, 0 > offset
Definition types.hh:144
Bitfield< 33 > id
Bitfield< 30, 0 > index
Bitfield< 0 > p
Bitfield< 3 > addr
Definition types.hh:84
Copyright (c) 2024 - Pranith Kumar Copyright (c) 2020 Inria 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
T htobe(T value)
Definition byteswap.hh:174
void ccprintf(cp::Print &print)
Definition cprintf.hh:130
reserved
Definition pcireg.h:54
PM4 packets.
const std::string & name()
Definition trace.cc:48

Generated on Tue Jun 18 2024 16:24:03 for gem5 by doxygen 1.11.0