gem5  v22.1.0.0
semihosting.cc
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2018, 2019 ARM Limited
3  * All rights reserved
4  *
5  * The license below extends only to copyright in the software and shall
6  * not be construed as granting a license to any other intellectual
7  * property including but not limited to intellectual property relating
8  * to a hardware implementation of the functionality of the software
9  * licensed hereunder. You may use the software subject to the license
10  * terms below provided that you ensure that this notice is replicated
11  * unmodified and in its entirety in all distributions of the software,
12  * modified or unmodified, in source code or in binary form.
13  *
14  * Redistribution and use in source and binary forms, with or without
15  * modification, are permitted provided that the following conditions are
16  * met: redistributions of source code must retain the above copyright
17  * notice, this list of conditions and the following disclaimer;
18  * redistributions in binary form must reproduce the above copyright
19  * notice, this list of conditions and the following disclaimer in the
20  * documentation and/or other materials provided with the distribution;
21  * neither the name of the copyright holders nor the names of its
22  * contributors may be used to endorse or promote products derived from
23  * this software without specific prior written permission.
24  *
25  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
26  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
27  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
28  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
29  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
30  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
31  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
32  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
33  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
34  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
35  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
36  */
37 
38 #include "arch/arm/semihosting.hh"
39 
40 #include <unistd.h>
41 
42 #include <cerrno>
43 #include <cstdio>
44 
45 #include "arch/arm/utility.hh"
46 #include "base/logging.hh"
47 #include "base/output.hh"
48 #include "base/time.hh"
49 #include "debug/Semihosting.hh"
50 #include "dev/serial/serial.hh"
51 #include "mem/physical.hh"
54 #include "params/ArmSemihosting.hh"
55 #include "sim/byteswap.hh"
56 #include "sim/full_system.hh"
57 #include "sim/pseudo_inst.hh"
58 #include "sim/sim_exit.hh"
59 #include "sim/system.hh"
60 
61 namespace gem5
62 {
63 
64 const std::map<uint32_t, ArmSemihosting::SemiCall> ArmSemihosting::calls{
65  { SYS_OPEN, { "SYS_OPEN", &ArmSemihosting::callOpen } },
66  { SYS_CLOSE, { "SYS_CLOSE", &ArmSemihosting::callClose } },
67  { SYS_WRITEC, { "SYS_WRITEC", &ArmSemihosting::callWriteC } },
68  { SYS_WRITE0, { "SYS_WRITE0", &ArmSemihosting::callWrite0 } },
69  { SYS_WRITE, { "SYS_WRITE", &ArmSemihosting::callWrite } },
70  { SYS_READ, { "SYS_READ", &ArmSemihosting::callRead } },
71  { SYS_READC, { "SYS_READC", &ArmSemihosting::callReadC } },
72  { SYS_ISERROR, { "SYS_ISERROR", &ArmSemihosting::callIsError } },
73  { SYS_ISTTY, { "SYS_ISTTY", &ArmSemihosting::callIsTTY } },
74  { SYS_SEEK, { "SYS_SEEK", &ArmSemihosting::callSeek } },
75  { SYS_FLEN, { "SYS_FLEN", &ArmSemihosting::callFLen } },
76  { SYS_TMPNAM, { "SYS_TMPNAM", &ArmSemihosting::callTmpNam } },
77  { SYS_REMOVE, { "SYS_REMOVE", &ArmSemihosting::callRemove } },
78  { SYS_RENAME, { "SYS_RENAME", &ArmSemihosting::callRename } },
79  { SYS_CLOCK, { "SYS_CLOCK", &ArmSemihosting::callClock } },
80  { SYS_TIME, { "SYS_TIME", &ArmSemihosting::callTime } },
81  { SYS_SYSTEM, { "SYS_SYSTEM", &ArmSemihosting::callSystem } },
82  { SYS_ERRNO, { "SYS_ERRNO", &ArmSemihosting::callErrno } },
83  { SYS_GET_CMDLINE,
84  { "SYS_GET_CMDLINE", &ArmSemihosting::callGetCmdLine } },
85  { SYS_HEAPINFO, { "SYS_HEAPINFO", &ArmSemihosting::callHeapInfo32,
87 
88  { SYS_EXIT, { "SYS_EXIT", &ArmSemihosting::callExit32,
90  { SYS_EXIT_EXTENDED,
91  { "SYS_EXIT_EXTENDED", &ArmSemihosting::callExitExtended } },
92 
93  { SYS_ELAPSED, { "SYS_ELAPSED", &ArmSemihosting::callElapsed32,
95  { SYS_TICKFREQ, { "SYS_TICKFREQ", &ArmSemihosting::callTickFreq } },
96  { SYS_GEM5_PSEUDO_OP,
97  { "SYS_GEM5_PSEUDO_OP", &ArmSemihosting::callGem5PseudoOp32,
99 };
100 
102  "r", "rb", "r+", "r+b",
103  "w", "wb", "w+", "w+b",
104  "a", "ab", "a+", "a+b",
105 };
106 
107 const std::map<uint64_t, const char *> ArmSemihosting::exitCodes{
108  { 0x20000, "semi:ADP_Stopped_BranchThroughZero" },
109  { 0x20001, "semi:ADP_Stopped_UndefinedInstr" },
110  { 0x20002, "semi:ADP_Stopped_SoftwareInterrupt" },
111  { 0x20003, "semi:ADP_Stopped_PrefetchAbort" },
112  { 0x20004, "semi:ADP_Stopped_DataAbort" },
113  { 0x20005, "semi:ADP_Stopped_AddressException" },
114  { 0x20006, "semi:ADP_Stopped_IRQ" },
115  { 0x20007, "semi:ADP_Stopped_FIQ" },
116 
117  { 0x20020, "semi:ADP_Stopped_BreakPoint" },
118  { 0x20021, "semi:ADP_Stopped_WatchPoint" },
119  { 0x20022, "semi:ADP_Stopped_StepComplete" },
120  { 0x20023, "semi:ADP_Stopped_RunTimeErrorUnknown" },
121  { 0x20024, "semi:ADP_Stopped_InternalError" },
122  { 0x20025, "semi:ADP_Stopped_UserInterruption" },
123  { 0x20026, "semi:ADP_Stopped_ApplicationExit" },
124  { 0x20027, "semi:ADP_Stopped_StackOverflow" },
125  { 0x20028, "semi:ADP_Stopped_DivisionByZero" },
126  { 0x20029, "semi:ADP_Stopped_DivisionByZero" },
127 };
128 
129 
131  0x53, 0x48, 0x46, 0x42, // Magic
132  0x3, // EXT_EXIT_EXTENDED, EXT_STDOUT_STDERR
133 };
134 
135 const std::map<const std::string, FILE *> ArmSemihosting::stdioMap{
136  {"cin", ::stdin},
137  {"stdin", ::stdin},
138  {"cout", ::stdout},
139  {"stdout", ::stdout},
140  {"cerr", ::stderr},
141  {"stderr", ::stderr},
142 };
143 
144 ArmSemihosting::ArmSemihosting(const ArmSemihostingParams &p)
145  : SimObject(p),
146  cmdLine(p.cmd_line),
147  memReserve(p.mem_reserve),
148  stackSize(p.stack_size),
149  timeBase([p]{ struct tm t = p.time; return mkutctime(&t); }()),
150  tickShift(calcTickShift()),
151  semiErrno(0),
152  filesRootDir(!p.files_root_dir.empty() &&
153  p.files_root_dir.back() != '/' ?
154  p.files_root_dir + '/' : p.files_root_dir),
155  stdin(getSTDIO("stdin", p.stdin, "r")),
156  stdout(getSTDIO("stdout", p.stdout, "w")),
157  stderr(p.stderr == p.stdout ?
158  stdout : getSTDIO("stderr", p.stderr, "w"))
159 {
160  // Create an empty place-holder file for position 0 as semi-hosting
161  // calls typically expect non-zero file handles.
162  files.push_back(nullptr);
163 
164  if (tickShift > 0)
165  inform("Semihosting: Shifting elapsed ticks by %i bits.",
166  tickShift);
167 }
168 
169 bool
171 {
172  RegVal op = tc->getReg(ArmISA::int_reg::X0) & mask(32);
173  if (op > MaxStandardOp && !gem5_ops) {
174  unrecognizedCall<Abi64>(
175  tc, "Gem5 semihosting op (0x%x) disabled from here.", op);
176  return false;
177  }
178 
179  auto it = calls.find(op);
180  if (it == calls.end()) {
181  unrecognizedCall<Abi64>(
182  tc, "Unknown aarch64 semihosting call: op = 0x%x", op);
183  return false;
184  }
185  const SemiCall &call = it->second;
186 
187  DPRINTF(Semihosting, "Semihosting call64: %s\n", call.dump64(tc));
188  auto err = call.call64(this, tc);
189  semiErrno = err.second;
190  DPRINTF(Semihosting, "\t ->: 0x%x, %i\n", err.first, err.second);
191 
192  return true;
193 }
194 
195 bool
197 {
199  if (op > MaxStandardOp && !gem5_ops) {
200  unrecognizedCall<Abi32>(
201  tc, "Gem5 semihosting op (0x%x) disabled from here.", op);
202  return false;
203  }
204 
205  auto it = calls.find(op);
206  if (it == calls.end()) {
207  unrecognizedCall<Abi32>(
208  tc, "Unknown aarch32 semihosting call: op = 0x%x", op);
209  return false;
210  }
211  const SemiCall &call = it->second;
212 
213  DPRINTF(Semihosting, "Semihosting call32: %s\n", call.dump32(tc));
214  auto err = call.call32(this, tc);
215  semiErrno = err.second;
216  DPRINTF(Semihosting, "\t ->: 0x%x, %i\n", err.first, err.second);
217 
218  return true;
219 }
220 
221 void
223 {
225 
226  paramOut(cp, "num_files", files.size());
227  for (int i = 0; i < files.size(); i++) {
228  // File closed?
229  if (!files[i])
230  continue;
231 
232  files[i]->serializeSection(cp, csprintf("file%i", i));
233  }
234 }
235 
236 void
238 {
240 
241  size_t num_files;
242  paramIn(cp, "num_files", num_files);
243  files.resize(num_files);
244  for (int i = 0; i < num_files; i++)
245  files[i] = FileBase::create(*this, cp, csprintf("file%i", i));
246 }
247 
248 PortProxy &
250 {
251  static std::unique_ptr<PortProxy> port_proxy_s;
252  static std::unique_ptr<PortProxy> port_proxy_ns;
253  static System *secure_sys = nullptr;
254 
255  if (ArmISA::isSecure(tc)) {
256  System *sys = tc->getSystemPtr();
257  if (sys != secure_sys) {
258  if (FullSystem) {
259  port_proxy_s.reset(
261  } else {
262  port_proxy_s.reset(
265  Request::SECURE));
266  }
267  }
268  secure_sys = sys;
269  return *port_proxy_s;
270  } else {
271  if (!port_proxy_ns) {
272  if (FullSystem) {
273  port_proxy_ns.reset(new TranslatingPortProxy(tc));
274  } else {
275  port_proxy_ns.reset(new SETranslatingPortProxy(tc));
276  }
277  }
278 
279  return *port_proxy_ns;
280  }
281 }
282 
283 
284 std::string
286 {
287  std::vector<char> buf(len + 1);
288 
289  buf[len] = '\0';
290  portProxy(tc).readBlob(ptr, buf.data(), len);
291 
292  return std::string(buf.data());
293 }
294 
297  int fmode, size_t name_size)
298 {
299  const char *mode = fmode < fmodes.size() ? fmodes[fmode] : nullptr;
300 
301  DPRINTF(Semihosting, "Semihosting SYS_OPEN(0x%x, %i[%s], %i)\n",
302  name_base, fmode, mode ? mode : "-", name_size);
303  if (!mode || !name_base)
304  return retError(EINVAL);
305 
306  std::string fname = readString(tc, name_base, name_size);
307  if (!fname.empty() && fname.front() != '/')
308  fname = filesRootDir + fname;
309 
310  std::unique_ptr<ArmSemihosting::FileBase> file =
311  FileBase::create(*this, fname, mode);
312  int64_t ret = file->open();
313  DPRINTF(Semihosting, "Semihosting SYS_OPEN(\"%s\", %i[%s]): %i\n",
314  fname, fmode, mode, ret);
315  if (ret < 0) {
316  return retError(-ret);
317  } else {
318  files.push_back(std::move(file));
319  return retOK(files.size() - 1);
320  }
321 }
322 
325 {
326  if (handle > files.size()) {
327  DPRINTF(Semihosting, "Semihosting SYS_CLOSE(%i): Illegal file\n");
328  return retError(EBADF);
329  }
330 
331  std::unique_ptr<FileBase> &file = files[handle];
332  int64_t error = file->close();
333  DPRINTF(Semihosting, "Semihosting SYS_CLOSE(%i[%s]): %i\n",
334  handle, file->fileName(), error);
335  if (error < 0) {
336  return retError(-error);
337  } else {
338  // Zap the pointer and free the entry in the file table as
339  // well.
340  files[handle].reset();
341  return retOK(0);
342  }
343 }
344 
347 {
348  const char c = portProxy(tc).read<char>(arg.addr);
349 
350  DPRINTF(Semihosting, "Semihosting SYS_WRITEC('%c')\n", c);
351  std::cout.put(c);
352 
353  return retOK(0);
354 }
355 
358 {
359  DPRINTF(Semihosting, "Semihosting SYS_WRITE0(...)\n");
360  PortProxy &proxy = portProxy(tc);
361  std::string str;
362  proxy.readString(str, arg.addr);
363  std::cout.write(str.c_str(), str.size());
364 
365  return retOK(0);
366 }
367 
370  size_t size)
371 {
372  if (handle > files.size() || !files[handle])
373  return RetErrno(size, EBADF);
374 
375  std::vector<uint8_t> buffer(size);
376  portProxy(tc).readBlob(addr, buffer.data(), buffer.size());
377 
378  int64_t ret = files[handle]->write(buffer.data(), buffer.size());
379  if (ret < 0) {
380  // No bytes written (we're returning the number of bytes not
381  // written)
382  return RetErrno(size, -ret);
383  } else {
384  // Return the number of bytes not written
385  return RetErrno(size - ret, 0);
386  }
387 }
388 
391  size_t size)
392 {
393  if (handle > files.size() || !files[handle])
394  return RetErrno(size, EBADF);
395 
396  std::vector<uint8_t> buffer(size);
397  int64_t ret = files[handle]->read(buffer.data(), buffer.size());
398  if (ret < 0) {
399  return RetErrno(size, -ret);
400  } else {
401  panic_if(ret > buffer.size(), "Read longer than buffer size.");
402 
403  portProxy(tc).writeBlob(addr, buffer.data(), ret);
404 
405  // Return the number of bytes not written
406  return retOK(size - ret);
407  }
408 }
409 
412 {
413  return retOK((char)std::cin.get());
414 }
415 
418 {
419  return retOK(status < 0 ? 1 : 0);
420 }
421 
424 {
425  if (handle > files.size() || !files[handle])
426  return retError(EBADF);
427 
428  int64_t ret = files[handle]->isTTY();
429  if (ret < 0) {
430  return retError(-ret);
431  } else {
432  return retOK(ret ? 1 : 0);
433  }
434 }
435 
438 {
439  if (handle > files.size() || !files[handle])
440  return retError(EBADF);
441 
442  int64_t ret = files[handle]->seek(pos);
443  if (ret < 0) {
444  return retError(-ret);
445  } else {
446  return retOK(0);
447  }
448 }
449 
452 {
453  if (handle > files.size() || !files[handle])
454  return retError(EBADF);
455 
456  int64_t ret = files[handle]->flen();
457  if (ret < 0) {
458  return retError(-ret);
459  } else {
460  return retOK(ret);
461  }
462 }
463 
466  size_t size)
467 {
468  std::string path = "";
469  int64_t unlink_call_ret = 0;
470 
471  do {
472  path = simout.resolve(csprintf("%s.tmp%05i", name(), tmpNameIndex++));
473  // remove the (potentially existing) file of the given path
474  unlink_call_ret = unlink(path.c_str());
475  // if the file is busy, find another name
476  } while ((unlink_call_ret < 0) && (errno == EBUSY));
477 
478  const size_t path_len = path.length();
479  if (path_len >= size)
480  return retError(ENOSPC);
481 
482  portProxy(tc).writeBlob(addr, path.c_str(), path_len + 1);
483  return retOK(0);
484 }
485 
487 ArmSemihosting::callRemove(ThreadContext *tc, Addr name_base, size_t name_size)
488 {
489  std::string fname = readString(tc, name_base, name_size);
490 
491  if (remove(fname.c_str()) != 0) {
492  return retError(errno);
493  } else {
494  return retOK(0);
495  }
496 }
497 
499 ArmSemihosting::callRename(ThreadContext *tc, Addr from_addr, size_t from_size,
500  Addr to_addr, size_t to_size)
501 {
502  std::string from = readString(tc, from_addr, from_size);
503  std::string to = readString(tc, to_addr, to_size);
504 
505  if (rename(from.c_str(), to.c_str()) != 0) {
506  return retError(errno);
507  } else {
508  return retOK(0);
509  }
510 }
511 
514 {
515  return retOK(curTick() / (sim_clock::as_int::s / 100));
516 }
517 
520 {
521  return retOK(timeBase + round(curTick() / sim_clock::as_float::s));
522 }
523 
525 ArmSemihosting::callSystem(ThreadContext *tc, Addr cmd_addr, size_t cmd_size)
526 {
527  const std::string cmd = readString(tc, cmd_addr, cmd_size);
528  warn("Semihosting: SYS_SYSTEM not implemented. Guest tried to run: %s\n",
529  cmd);
530  return retError(EINVAL);
531 
532 }
533 
536 {
537  // Preserve errno by returning it in errno as well.
538  return RetErrno(semiErrno, semiErrno);
539 }
540 
543  InPlaceArg size_arg)
544 {
545  PortProxy &proxy = portProxy(tc);
546  ByteOrder endian = ArmISA::byteOrder(tc);
547  size_t size = size_arg.read(tc, endian);
548 
549  if (cmdLine.size() + 1 < size) {
550  proxy.writeBlob(addr, cmdLine.c_str(), cmdLine.size() + 1);
551  size_arg.write(tc, cmdLine.size(), endian);
552  return retOK(0);
553  } else {
554  return retError(0);
555  }
556 }
557 
558 void
560  Addr &heap_base, Addr &heap_limit,
561  Addr &stack_base, Addr &stack_limit)
562 {
563  const memory::PhysicalMemory &phys = tc->getSystemPtr()->getPhysMem();
564  const AddrRangeList memories = phys.getConfAddrRanges();
565  fatal_if(memories.size() < 1, "No memories reported from System");
566  warn_if(memories.size() > 1, "Multiple physical memory ranges available. "
567  "Using first range heap/stack.");
568  const AddrRange mem = *memories.begin();
569  const Addr mem_start = mem.start() + memReserve;
570  Addr mem_end = mem.end();
571 
572  // Make sure that 32-bit guests can access their memory.
573  if (!aarch64) {
574  const Addr phys_max = (1ULL << 32) - 1;
575  panic_if(mem_start > phys_max,
576  "Physical memory out of range for a 32-bit guest.");
577  if (mem_end > phys_max) {
578  warn("Some physical memory out of range for a 32-bit guest.");
579  mem_end = phys_max;
580  }
581  }
582 
583  fatal_if(mem_start + stackSize >= mem_end,
584  "Physical memory too small to fit desired stack and a heap.");
585 
586  heap_base = mem_start;
587  heap_limit = mem_end - stackSize + 1;
588  stack_base = (mem_end + 1) & ~0x7ULL; // 8 byte stack alignment
589  stack_limit = heap_limit;
590 
591  inform("Reporting heap/stack info to guest:\n"
592  "\tHeap base: 0x%x\n"
593  "\tHeap limit: 0x%x\n"
594  "\tStack base: 0x%x\n"
595  "\tStack limit: 0x%x\n",
596  heap_base, heap_limit, stack_base, stack_limit);
597 }
598 
601 {
602  uint64_t heap_base, heap_limit, stack_base, stack_limit;
603  gatherHeapInfo(tc, false, heap_base, heap_limit, stack_base, stack_limit);
604 
605  std::array<uint32_t, 4> block = {{
606  (uint32_t)heap_base, (uint32_t)heap_limit,
607  (uint32_t)stack_base, (uint32_t)stack_limit
608  }};
609  portProxy(tc).write(block_addr, block, ArmISA::byteOrder(tc));
610 
611  return retOK(0);
612 }
613 
616 {
617  uint64_t heap_base, heap_limit, stack_base, stack_limit;
618  gatherHeapInfo(tc, true, heap_base, heap_limit, stack_base, stack_limit);
619 
620  std::array<uint64_t, 4> block = {{
621  heap_base, heap_limit, stack_base, stack_limit
622  }};
623  portProxy(tc).write(block_addr, block, ArmISA::byteOrder(tc));
624 
625  return retOK(0);
626 }
627 
630 {
631  semiExit(code.addr, 0);
632  return retOK(0);
633 }
634 
636 ArmSemihosting::callExit64(ThreadContext *tc, uint64_t code, uint64_t subcode)
637 {
638  semiExit(code, subcode);
639  return retOK(0);
640 }
641 
644  uint64_t code, uint64_t subcode)
645 {
646  semiExit(code, subcode);
647  return retOK(0);
648 }
649 
650 void
651 ArmSemihosting::semiExit(uint64_t code, uint64_t subcode)
652 {
653  auto it = exitCodes.find(code);
654  if (it != exitCodes.end()) {
655  exitSimLoop(it->second, subcode);
656  } else {
657  exitSimLoop(csprintf("semi:0x%x", code), subcode);
658  }
659 }
660 
661 
665 {
666  ByteOrder endian = ArmISA::byteOrder(tc);
667  uint64_t tick = semiTick(curTick());
668 
669  low.write(tc, tick, endian);
670  high.write(tc, tick >> 32, endian);
671 
672  return retOK(0);
673 }
674 
675 
678 {
679  ticks.write(tc, semiTick(curTick()), ArmISA::byteOrder(tc));
680  return retOK(0);
681 }
682 
683 
686 {
688 }
689 
690 
692 {
694  {
695  public:
696  State(const ThreadContext *tc) : ArmSemihosting::Abi32::State(tc)
697  {
698  // Use getAddr() to skip the func number in the first slot.
699  getAddr();
700  }
701  };
702 };
703 
705 {
707  {
708  public:
709  State(const ThreadContext *tc) : ArmSemihosting::Abi64::State(tc)
710  {
711  // Use getAddr() to skip the func number in the first slot.
712  getAddr();
713  }
714  };
715 };
716 
717 GEM5_DEPRECATED_NAMESPACE(GuestABI, guest_abi);
718 namespace guest_abi
719 {
720 
721 // Handle arguments the same as for semihosting operations. Skipping the first
722 // slot is handled internally by the State type.
723 template <typename T>
725  public Argument<ArmSemihosting::Abi32, T>
726 {};
727 template <typename T>
729  public Argument<ArmSemihosting::Abi64, T>
730 {};
731 
732 } // namespace guest_abi
733 
736 {
737  uint8_t func;
738  pseudo_inst::decodeAddrOffset(encoded_func, func);
739 
740  uint64_t ret;
741  if (pseudo_inst::pseudoInst<SemiPseudoAbi32>(tc, func, ret))
742  return retOK(ret);
743  else
744  return retError(EINVAL);
745 }
746 
749 {
750  uint8_t func;
751  pseudo_inst::decodeAddrOffset(encoded_func, func);
752 
753  uint64_t ret;
754  if (pseudo_inst::pseudoInst<SemiPseudoAbi64>(tc, func, ret))
755  return retOK(ret);
756  else
757  return retError(EINVAL);
758 }
759 
760 FILE *
761 ArmSemihosting::getSTDIO(const char *stream_name,
762  const std::string &name, const char *mode)
763 {
764  auto it = stdioMap.find(name);
765  if (it == stdioMap.end()) {
766  FILE *f = fopen(name.c_str(), mode);
767  if (!f) {
768  fatal("Failed to open %s (%s): %s\n",
769  stream_name, name, strerror(errno));
770  }
771  return f;
772  } else {
773  return it->second;
774  }
775 }
776 
777 std::unique_ptr<ArmSemihosting::FileBase>
779  ArmSemihosting &parent, const std::string &fname, const char *mode)
780 {
781  std::unique_ptr<FileBase> file;
782  if (fname == ":semihosting-features") {
783  file.reset(new FileFeatures(parent, fname.c_str(), mode));
784  } else {
785  file.reset(new File(parent, fname.c_str(), mode));
786  }
787 
788  return file;
789 }
790 
791 std::unique_ptr<ArmSemihosting::FileBase>
793  CheckpointIn &cp, const std::string &sec)
794 {
795  std::unique_ptr<FileBase> file;
796  ScopedCheckpointSection _sec(cp, sec);
797 
798  // Was the file open when the checkpoint was created?
800  return file;
801 
802  std::string fname, mode;
803  paramIn(cp, "name", fname);
804  paramIn(cp, "mode", mode);
805  file = create(parent, fname, mode.c_str());
806  assert(file);
807  file->unserialize(cp);
808 
809  return file;
810 }
811 
812 void
814 {
815  paramOut(cp, "name", _name);
817 }
818 
819 void
821 {
822  /* Unserialization of name and mode happens in
823  * ArmSemihosting::FileBase::create() */
824 }
825 
826 int64_t
827 ArmSemihosting::FileBase::read(uint8_t *buffer, uint64_t size)
828 {
829  return -EINVAL;
830 }
831 
832 int64_t
833 ArmSemihosting::FileBase::write(const uint8_t *buffer, uint64_t size)
834 {
835  return -EINVAL;
836 }
837 
838 int64_t
840 {
841  return -EINVAL;
842 }
843 
844 int64_t
846 {
847  return -EINVAL;
848 }
849 
850 
852  ArmSemihosting &_parent, const char *_name, const char *_mode)
853  : FileBase(_parent, _name, _mode)
854 {
855 }
856 
857 int64_t
858 ArmSemihosting::FileFeatures::read(uint8_t *buffer, uint64_t size)
859 {
860  int64_t len = 0;
861 
862  for (; pos < size && pos < ArmSemihosting::features.size(); pos++)
863  buffer[len++] = ArmSemihosting::features[pos];
864 
865  return len;
866 }
867 
868 int64_t
870 {
871  if (_pos < ArmSemihosting::features.size()) {
872  pos = _pos;
873  return 0;
874  } else {
875  return -ENXIO;
876  }
877 }
878 
879 void
881 {
883  SERIALIZE_SCALAR(pos);
884 }
885 
886 void
888 {
890  UNSERIALIZE_SCALAR(pos);
891 }
892 
893 
894 
896  const char *_name, const char *_perms)
897  : FileBase(_parent, _name, _perms),
898  file(nullptr)
899 {
900 }
901 
903 {
904  if (file)
905  close();
906 }
907 
908 int64_t
910 {
911  panic_if(file, "Trying to open an already open file.\n");
912 
913  if (_name == ":tt") {
914  if (mode[0] == 'r') {
915  file = parent.stdin;
916  } else if (mode[0] == 'w') {
917  file = parent.stdout;
918  } else if (mode[0] == 'a') {
919  file = parent.stderr;
920  } else {
921  warn("Unknown file mode for the ':tt' special file");
922  return -EINVAL;
923  }
924  } else {
925  std::string real_mode(this->mode);
926  // Avoid truncating the file if we are restoring from a
927  // checkpoint.
928  if (in_cpt && real_mode[0] == 'w')
929  real_mode[0] = 'a';
930 
931  file = fopen(_name.c_str(), real_mode.c_str());
932  }
933 
934  return file ? 0 : -errno;
935 }
936 
937 int64_t
939 {
940  panic_if(!file, "Trying to close an already closed file.\n");
941 
942  if (needClose()) {
943  fclose(file);
944  }
945  file = nullptr;
946 
947  return 0;
948 }
949 
950 bool
952 {
953  return file == parent.stdout ||
954  file == parent.stderr ||
955  file == parent.stdin;
956 }
957 
958 int64_t
959 ArmSemihosting::File::read(uint8_t *buffer, uint64_t size)
960 {
961  panic_if(!file, "Trying to read from a closed file");
962 
963  size_t ret = fread(buffer, 1, size, file);
964  if (ret == 0) {
965  // Error or EOF. Assume errors are due to invalid file
966  // operations (e.g., reading a write-only stream).
967  return ferror(file) ? -EINVAL : 0;
968  } else {
969  return ret;
970  }
971 }
972 
973 int64_t
974 ArmSemihosting::File::write(const uint8_t *buffer, uint64_t size)
975 {
976  panic_if(!file, "Trying to write to a closed file");
977 
978 
979  size_t ret = fwrite(buffer, 1, size, file);
980  if (ret == 0) {
981  // Assume errors are due to invalid file operations (e.g.,
982  // writing a read-only stream).
983  return -EINVAL;
984  } else {
985  return ret;
986  }
987 }
988 
989 int64_t
991 {
992  panic_if(!file, "Trying to seek in a closed file");
993 
994  errno = 0;
995  if (fseek(file, _pos, SEEK_SET) == 0)
996  return 0;
997  else
998  return -errno;
999 }
1000 
1001 int64_t
1003 {
1004  errno = 0;
1005  long pos = ftell(file);
1006  if (pos < 0)
1007  return -errno;
1008 
1009  if (fseek(file, 0, SEEK_END) != 0)
1010  return -errno;
1011 
1012  long len = ftell(file);
1013  if (len < 0)
1014  return -errno;
1015 
1016  if (fseek(file, pos, SEEK_SET) != 0)
1017  return -errno;
1018 
1019  return len;
1020 }
1021 
1022 
1023 void
1025 {
1026  FileBase::serialize(cp);
1027 
1028  if (!isTTY()) {
1029  long pos = file ? ftell(file) : 0;
1030  panic_if(pos < 0, "Failed to get file position.");
1031  SERIALIZE_SCALAR(pos);
1032  }
1033 }
1034 
1035 void
1037 {
1039 
1040  if (openImpl(true) < 0) {
1041  fatal("Failed to open file: %s", _name);
1042  }
1043 
1044  if (!isTTY()) {
1045  long pos = 0;
1046  UNSERIALIZE_SCALAR(pos);
1047  if (fseek(file, pos, SEEK_SET) != 0) {
1048  fatal("Failed seek to current position (%i) in '%s'", pos, _name);
1049  }
1050  }
1051 }
1052 
1053 std::ostream &
1054 operator << (std::ostream &os, const ArmSemihosting::InPlaceArg &ipa)
1055 {
1056  ccprintf(os, "[%#x-%#x)", ipa.addr, ipa.addr + ipa.size - 1);
1057  return os;
1058 }
1059 
1060 } // namespace gem5
std::string error
Definition: remote_gdb.cc:212
#define DPRINTF(x,...)
Definition: trace.hh:186
The AddrRange class encapsulates an address range, and supports a number of tests to check if two ran...
Definition: addr_range.hh:82
Internal state for open files.
Definition: semihosting.hh:280
virtual int64_t seek(uint64_t pos)
Seek to an absolute position in the file.
Definition: semihosting.cc:839
virtual int64_t write(const uint8_t *buffer, uint64_t size)
Write data to file.
Definition: semihosting.cc:833
virtual int64_t read(uint8_t *buffer, uint64_t size)
Read data from file.
Definition: semihosting.cc:827
virtual int64_t flen()
Get the length of a file in bytes.
Definition: semihosting.cc:845
void serialize(CheckpointOut &cp) const override
Serialize an object.
Definition: semihosting.cc:813
void unserialize(CheckpointIn &cp) override
Unserialize an object.
Definition: semihosting.cc:820
static std::unique_ptr< FileBase > create(ArmSemihosting &parent, const std::string &fname, const char *mode)
Definition: semihosting.cc:778
Implementation of the ':semihosting-features' magic file.
Definition: semihosting.hh:371
FileFeatures(ArmSemihosting &_parent, const char *name, const char *mode)
Definition: semihosting.cc:851
int64_t seek(uint64_t pos) override
Seek to an absolute position in the file.
Definition: semihosting.cc:869
void unserialize(CheckpointIn &cp) override
Unserialize an object.
Definition: semihosting.cc:887
int64_t read(uint8_t *buffer, uint64_t size) override
Read data from file.
Definition: semihosting.cc:858
void serialize(CheckpointOut &cp) const override
Serialize an object.
Definition: semihosting.cc:880
File(ArmSemihosting &_parent, const char *name, const char *mode)
Definition: semihosting.cc:895
int64_t openImpl(bool unserialize)
Definition: semihosting.cc:909
int64_t write(const uint8_t *buffer, uint64_t size) override
Write data to file.
Definition: semihosting.cc:974
int64_t seek(uint64_t pos) override
Seek to an absolute position in the file.
Definition: semihosting.cc:990
int64_t close() override
Close the file.
Definition: semihosting.cc:938
void serialize(CheckpointOut &cp) const override
Serialize an object.
bool isTTY() const override
Check if a file corresponds to a TTY device.
Definition: semihosting.cc:951
int64_t read(uint8_t *buffer, uint64_t size) override
Read data from file.
Definition: semihosting.cc:959
int64_t flen() override
Get the length of a file in bytes.
void unserialize(CheckpointIn &cp) override
Unserialize an object.
Semihosting for AArch32 and AArch64.
Definition: semihosting.hh:77
std::pair< uint64_t, SemiErrno > RetErrno
Definition: semihosting.hh:433
void serialize(CheckpointOut &cp) const override
Serialize an object.
Definition: semihosting.cc:222
RetErrno callSeek(ThreadContext *tc, Handle handle, uint64_t pos)
Definition: semihosting.cc:437
RetErrno callReadC(ThreadContext *tc)
Definition: semihosting.cc:411
static const std::map< uint32_t, SemiCall > calls
Definition: semihosting.hh:588
RetErrno callSystem(ThreadContext *tc, Addr cmd_addr, size_t cmd_size)
Definition: semihosting.cc:525
RetErrno callExitExtended(ThreadContext *tc, uint64_t code, uint64_t subcode)
Definition: semihosting.cc:643
RetErrno callRename(ThreadContext *tc, Addr from_addr, size_t from_size, Addr to_addr, size_t to_size)
Definition: semihosting.cc:499
RetErrno callClock(ThreadContext *tc)
Definition: semihosting.cc:513
bool call32(ThreadContext *tc, bool gem5_ops)
Perform an Arm Semihosting call from aarch32 code.
Definition: semihosting.cc:196
RetErrno callTickFreq(ThreadContext *tc)
Definition: semihosting.cc:685
RetErrno callWriteC(ThreadContext *tc, InPlaceArg c)
Definition: semihosting.cc:346
RetErrno callTime(ThreadContext *tc)
Definition: semihosting.cc:519
static const std::map< const std::string, FILE * > stdioMap
Definition: semihosting.hh:592
static RetErrno retOK(uint64_t r)
Definition: semihosting.hh:443
RetErrno callGetCmdLine(ThreadContext *tc, Addr addr, InPlaceArg size_arg)
Definition: semihosting.cc:542
RetErrno callIsError(ThreadContext *tc, int64_t status)
Definition: semihosting.cc:417
std::string filesRootDir
Definition: semihosting.hh:410
void gatherHeapInfo(ThreadContext *tc, bool aarch64, Addr &heap_base, Addr &heap_limit, Addr &stack_base, Addr &stack_limit)
Definition: semihosting.cc:559
static PortProxy & portProxy(ThreadContext *tc)
Definition: semihosting.cc:249
std::string readString(ThreadContext *tc, Addr ptr, size_t len)
Definition: semihosting.cc:285
RetErrno callWrite0(ThreadContext *tc, InPlaceArg str)
Definition: semihosting.cc:357
bool call64(ThreadContext *tc, bool gem5_ops)
Perform an Arm Semihosting call from aarch64 code.
Definition: semihosting.cc:170
RetErrno callElapsed64(ThreadContext *tc, InPlaceArg ticks)
Definition: semihosting.cc:677
void semiExit(uint64_t code, uint64_t subcode)
Definition: semihosting.cc:651
const time_t timeBase
Base time when the simulation started.
Definition: semihosting.hh:256
static FILE * getSTDIO(const char *stream_name, const std::string &name, const char *mode)
Definition: semihosting.cc:761
static const std::map< uint64_t, const char * > exitCodes
Definition: semihosting.hh:590
void unserialize(CheckpointIn &cp) override
Unserialize an object.
Definition: semihosting.cc:237
RetErrno callRemove(ThreadContext *tc, Addr name_base, size_t name_size)
Definition: semihosting.cc:487
RetErrno callFLen(ThreadContext *tc, Handle handle)
Definition: semihosting.cc:451
RetErrno callIsTTY(ThreadContext *tc, Handle handle)
Definition: semihosting.cc:423
RetErrno callClose(ThreadContext *tc, Handle handle)
Definition: semihosting.cc:324
RetErrno callHeapInfo64(ThreadContext *tc, Addr block_addr)
Definition: semihosting.cc:615
std::vector< std::unique_ptr< FileBase > > files
Definition: semihosting.hh:411
RetErrno callExit64(ThreadContext *tc, uint64_t code, uint64_t subcode)
Definition: semihosting.cc:636
RetErrno callGem5PseudoOp32(ThreadContext *tc, uint32_t encoded_func)
Definition: semihosting.cc:735
RetErrno callTmpNam(ThreadContext *tc, Addr buffer, uint64_t id, size_t size)
Definition: semihosting.cc:465
RetErrno callRead(ThreadContext *tc, Handle handle, Addr buffer, size_t size)
Definition: semihosting.cc:390
static const std::vector< uint8_t > features
Definition: semihosting.hh:591
RetErrno callHeapInfo32(ThreadContext *tc, Addr block_addr)
Definition: semihosting.cc:600
ArmSemihosting(const ArmSemihostingParams &p)
Definition: semihosting.cc:144
uint64_t semiTick(Tick tick) const
Definition: semihosting.hh:425
static const std::vector< const char * > fmodes
Definition: semihosting.hh:589
RetErrno callWrite(ThreadContext *tc, Handle handle, Addr buffer, size_t size)
Definition: semihosting.cc:369
RetErrno callGem5PseudoOp64(ThreadContext *tc, uint64_t encoded_func)
Definition: semihosting.cc:748
RetErrno callExit32(ThreadContext *tc, InPlaceArg code)
Definition: semihosting.cc:629
RetErrno callOpen(ThreadContext *tc, const Addr name_base, int fmode, size_t name_size)
Definition: semihosting.cc:296
static RetErrno retError(SemiErrno e)
Definition: semihosting.hh:437
RetErrno callElapsed32(ThreadContext *tc, InPlaceArg low, InPlaceArg high)
Definition: semihosting.cc:663
RetErrno callErrno(ThreadContext *tc)
Definition: semihosting.cc:535
const std::string cmdLine
Definition: semihosting.hh:248
const std::string _name
Definition: named.hh:41
virtual std::string name() const
Definition: named.hh:47
std::string resolve(const std::string &name) const
Returns relative file names prepended with name of this directory.
Definition: output.cc:204
This object is a proxy for a port or other object which implements the functional response protocol,...
Definition: port_proxy.hh:87
T read(Addr address) const
Read sizeof(T) bytes from address and return as object T.
Definition: port_proxy.hh:287
void writeBlob(Addr addr, const void *p, int size) const
Same as tryWriteBlob, but insists on success.
Definition: port_proxy.hh:192
void write(Addr address, const T &data) const
Write object T to address.
Definition: port_proxy.hh:296
void readString(std::string &str, Addr addr) const
Same as tryReadString, but insists on success.
Definition: port_proxy.hh:260
void readBlob(Addr addr, void *p, int size) const
Higher level interfaces based on the above.
Definition: port_proxy.hh:182
@ SECURE
The request targets the secure memory space.
Definition: request.hh:186
State(const ThreadContext *tc)
Definition: semihosting.cc:696
State(const ThreadContext *tc)
Definition: semihosting.cc:709
static std::stack< std::string > path
Definition: serialize.hh:315
Abstract superclass for simulation objects.
Definition: sim_object.hh:148
memory::PhysicalMemory & getPhysMem()
Get a pointer to access the physical memory of the system.
Definition: system.hh:345
ThreadContext is the external interface to all thread state for anything outside of the CPU.
virtual RegVal getReg(const RegId &reg) const
virtual System * getSystemPtr()=0
This proxy attempts to translate virtual addresses using the TLBs.
The physical memory encapsulates all memories in the system and provides basic functionality for acce...
Definition: physical.hh:137
AddrRangeList getConfAddrRanges() const
Get the memory ranges for all memories that are to be reported to the configuration table.
Definition: physical.cc:279
STL pair class.
Definition: stl.hh:58
constexpr uint64_t mask(unsigned nbits)
Generate a 64-bit mask of 'nbits' 1s, right justified.
Definition: bitfield.hh:63
#define fatal_if(cond,...)
Conditional fatal macro that checks the supplied condition and only causes a fatal error if the condi...
Definition: logging.hh:226
#define fatal(...)
This implements a cprintf based fatal() function.
Definition: logging.hh:190
#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
static const std::string & currentSection()
Gets the fully-qualified name of the active section.
Definition: serialize.cc:130
bool sectionExists(const std::string &section)
Definition: serialize.cc:200
uint16_t len
Definition: helpers.cc:62
#define warn(...)
Definition: logging.hh:246
#define warn_if(cond,...)
Conditional warning macro that checks the supplied condition and only prints a warning if the conditi...
Definition: logging.hh:273
#define inform(...)
Definition: logging.hh:247
constexpr RegId X0
Definition: int.hh:240
constexpr RegId R0
Definition: int.hh:186
ByteOrder byteOrder(const ThreadContext *tc)
Definition: utility.hh:357
Bitfield< 4, 0 > mode
Definition: misc_types.hh:74
bool isSecure(ThreadContext *tc)
Definition: utility.cc:74
Bitfield< 6 > err
Definition: misc_types.hh:809
Bitfield< 7 > i
Definition: misc_types.hh:67
Bitfield< 5, 0 > status
Definition: misc_types.hh:429
Bitfield< 34 > aarch64
Definition: types.hh:81
Bitfield< 25, 21 > to
Definition: types.hh:96
Bitfield< 32 > tm
Definition: misc.hh:112
Bitfield< 2 > c
Definition: pagetable.hh:63
Bitfield< 51 > t
Definition: pagetable.hh:56
Bitfield< 56 > f
Definition: pagetable.hh:53
Bitfield< 54 > p
Definition: pagetable.hh:70
Bitfield< 17 > os
Definition: misc.hh:810
Bitfield< 4 > op
Definition: types.hh:83
Bitfield< 3 > addr
Definition: types.hh:84
static void decodeAddrOffset(Addr offset, uint8_t &func)
Definition: pseudo_inst.hh:63
double s
These variables equal the number of ticks in the unit of time they're named after in a double.
Definition: core.cc:53
Tick s
second
Definition: core.cc:68
Tick Frequency
The simulated frequency of curTick(). (In ticks per second)
Definition: core.cc:48
Reference material can be found at the JEDEC website: UFS standard http://www.jedec....
high
Definition: intmath.hh:176
Tick curTick()
The universal simulation clock.
Definition: cur_tick.hh:46
std::ostream CheckpointOut
Definition: serialize.hh:66
uint64_t Addr
Address type This will probably be moved somewhere else in the near future.
Definition: types.hh:147
void paramOut(CheckpointOut &cp, const std::string &name, ExtMachInst const &machInst)
Definition: types.cc:40
time_t mkutctime(struct tm *time)
Definition: time.cc:154
std::ostream & operator<<(std::ostream &os, const ArmSemihosting::InPlaceArg &ipa)
void paramIn(CheckpointIn &cp, const std::string &name, ExtMachInst &machInst)
Definition: types.cc:72
bool FullSystem
The FullSystem variable can be used to determine the current mode of simulation.
Definition: root.cc:220
OutputDirectory simout
Definition: output.cc:62
void exitSimLoop(const std::string &message, int exit_code, Tick when, Tick repeat, bool serialize)
Schedule an event to exit the simulation loop (returning to Python) at the end of the current cycle (...
Definition: sim_events.cc:88
uint64_t RegVal
Definition: types.hh:173
std::string csprintf(const char *format, const Args &...args)
Definition: cprintf.hh:161
void ccprintf(cp::Print &print)
Definition: cprintf.hh:130
GEM5_DEPRECATED_NAMESPACE(GuestABI, guest_abi)
#define UNSERIALIZE_SCALAR(scalar)
Definition: serialize.hh:575
#define SERIALIZE_SCALAR(scalar)
Definition: serialize.hh:568
uint64_t read(ThreadContext *tc, ByteOrder endian)
Definition: semihosting.hh:179
void write(ThreadContext *tc, uint64_t val, ByteOrder endian)
Definition: semihosting.hh:192
Semihosting call information structure.
Definition: semihosting.hh:456
bool_vector8 mem[]
Definition: reset_stim.h:43
const std::string & name()
Definition: trace.cc:49

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