gem5  v22.1.0.0
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 
43 namespace gem5
44 {
45 
46 namespace qemu
47 {
48 
49 void
50 FwCfgItemFixed::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 
79 FwCfg::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 
112  addItem(&directory);
113 };
114 
115 void
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 
135 void
136 FwCfg::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 
159 void
160 FwCfg::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 
187 void
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 
234 Tick
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 
261 Tick
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 
296 Tick
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 
323 Tick
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:186
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:294
T * getPtr()
get a pointer to the data ptr.
Definition: packet.hh:1212
Addr getAddr() const
Definition: packet.hh:805
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:1059
unsigned getSize() const
Definition: packet.hh:815
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
void read(void *buf, uint64_t offset, uint32_t to_read) override
Definition: fw_cfg.cc:50
virtual const void * bytes() const =0
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:178
#define panic_if(cond,...)
Conditional panic macro that checks the supplied condition and only panics if the condition is true a...
Definition: logging.hh:204
#define warn(...)
Definition: logging.hh:246
Bitfield< 23, 0 > offset
Definition: types.hh:144
Bitfield< 33 > id
Definition: misc_types.hh:257
Bitfield< 30, 0 > index
Bitfield< 54 > p
Definition: pagetable.hh:70
Bitfield< 3 > addr
Definition: types.hh:84
Reference material can be found at the JEDEC website: UFS standard http://www.jedec....
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
static void overflow(double &c, const scfx_params &params, bool &o_flag)
Definition: sc_fxnum.cc:428
reserved
Definition: pcireg.h:54
PM4 packets.
Definition: pm4_defines.hh:78

Generated on Wed Dec 21 2022 10:22:34 for gem5 by doxygen 1.9.1