gem5 v24.1.0.1
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
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
39
40#include <unistd.h>
41
42#include <cerrno>
43#include <cstdio>
44
45#include "base/logging.hh"
46#include "base/output.hh"
47#include "base/time.hh"
48#include "debug/Semihosting.hh"
49#include "dev/serial/serial.hh"
50#include "mem/physical.hh"
51#include "params/BaseSemihosting.hh"
52#include "sim/byteswap.hh"
53#include "sim/pseudo_inst.hh"
54#include "sim/sim_exit.hh"
55#include "sim/system.hh"
56
57namespace gem5
58{
59
61 "r",
62 "rb",
63 "r+",
64 "r+b",
65 "w",
66 "wb",
67 "w+",
68 "w+b",
69 "a",
70 "ab",
71 "a+",
72 "a+b",
73};
74
75const std::map<uint64_t, const char *> BaseSemihosting::exitCodes{
76 {0x20000, "semi:ADP_Stopped_BranchThroughZero"},
77 {0x20001, "semi:ADP_Stopped_UndefinedInstr"},
78 {0x20002, "semi:ADP_Stopped_SoftwareInterrupt"},
79 {0x20003, "semi:ADP_Stopped_PrefetchAbort"},
80 {0x20004, "semi:ADP_Stopped_DataAbort"},
81 {0x20005, "semi:ADP_Stopped_AddressException"},
82 {0x20006, "semi:ADP_Stopped_IRQ"},
83 {0x20007, "semi:ADP_Stopped_FIQ"},
84
85 {0x20020, "semi:ADP_Stopped_BreakPoint"},
86 {0x20021, "semi:ADP_Stopped_WatchPoint"},
87 {0x20022, "semi:ADP_Stopped_StepComplete"},
88 {0x20023, "semi:ADP_Stopped_RunTimeErrorUnknown"},
89 {0x20024, "semi:ADP_Stopped_InternalError"},
90 {0x20025, "semi:ADP_Stopped_UserInterruption"},
91 {0x20026, "semi:ADP_Stopped_ApplicationExit"},
92 {0x20027, "semi:ADP_Stopped_StackOverflow"},
93 {0x20028, "semi:ADP_Stopped_DivisionByZero"},
94 {0x20029, "semi:ADP_Stopped_DivisionByZero"},
95};
96
97const std::array<uint8_t, 5> BaseSemihosting::features{
98 0x53, 0x48, 0x46, 0x42, // Magic
99 0x3, // EXT_EXIT_EXTENDED, EXT_STDOUT_STDERR
100};
101
102const std::map<const std::string, FILE *> BaseSemihosting::stdioMap{
103 {"cin", ::stdin},
104 {"stdin", ::stdin},
105 {"cout", ::stdout},
106 {"stdout", ::stdout},
107 {"cerr", ::stderr},
108 {"stderr", ::stderr},
109};
110
111BaseSemihosting::BaseSemihosting(const BaseSemihostingParams &p)
112 : SimObject(p), cmdLine(p.cmd_line), memReserve(p.mem_reserve),
113 stackSize(p.stack_size), timeBase([p] {
114 struct tm t = p.time;
115 return mkutctime(&t);
116 }()),
117 tickShift(calcTickShift()), semiErrno(0),
118 filesRootDir(!p.files_root_dir.empty() && p.files_root_dir.back() != '/' ?
119 p.files_root_dir + '/' :
120 p.files_root_dir),
121 stdin(getSTDIO("stdin", p.stdin, "r")),
122 stdout(getSTDIO("stdout", p.stdout, "w")),
123 stderr(p.stderr == p.stdout ? stdout : getSTDIO("stderr", p.stderr, "w"))
124{
125 // Create an empty place-holder file for position 0 as semi-hosting
126 // calls typically expect non-zero file handles.
127 files.push_back(nullptr);
128
129 if (tickShift > 0)
130 inform("Semihosting: Shifting elapsed ticks by %i bits.", tickShift);
131}
132
133void
135{
137
138 paramOut(cp, "num_files", files.size());
139 for (int i = 0; i < files.size(); i++) {
140 // File closed?
141 if (!files[i])
142 continue;
143
144 files[i]->serializeSection(cp, csprintf("file%i", i));
145 }
146}
147
148void
150{
152
153 size_t num_files;
154 paramIn(cp, "num_files", num_files);
155 files.resize(num_files);
156 for (int i = 0; i < num_files; i++)
157 files[i] = FileBase::create(*this, cp, csprintf("file%i", i));
158}
159
160std::optional<std::string>
162{
163 if (len > 65536) {
164 // If the semihosting call passes an incorrect argument, reject it rather
165 // than attempting to allocate a buffer of that size. We chose 64K as
166 // an arbitrary limit here since no valid program should be attempting
167 // to open a file with such a large filename.
168 warn("BaseSemihosting::readString(): attempting to read too large "
169 "(%d bytes) string from %#x", len, ptr);
170 return std::nullopt;
171 }
172 std::vector<char> buf(len + 1);
173
174 buf[len] = '\0';
175 portProxy(tc).readBlob(ptr, buf.data(), len);
176
177 return std::string(buf.data());
178}
179
182 ThreadContext *tc, const Addr name_base, int fmode, size_t name_size)
183{
184 const char *mode = fmode < fmodes.size() ? fmodes[fmode] : nullptr;
185
186 DPRINTF(Semihosting, "Semihosting SYS_OPEN(0x%x, %i[%s], %i)\n", name_base,
187 fmode, mode ? mode : "-", name_size);
188 if (!mode || !name_base)
189 return retError(EINVAL);
190
191 std::optional<std::string> fnameOpt = readString(tc, name_base, name_size);
192 if (!fnameOpt.has_value())
193 return retError(ERANGE);
194 std::string fname = *fnameOpt;
195 if (!fname.empty() && fname.front() != '/' && fname != ":tt" &&
196 fname != ":semihosting-features")
197 fname = filesRootDir + fname;
198
199 std::unique_ptr<BaseSemihosting::FileBase> file =
200 FileBase::create(*this, fname, mode);
201 int64_t ret = file->open();
202 DPRINTF(Semihosting, "Semihosting SYS_OPEN(\"%s\", %i[%s]): %i\n", fname,
203 fmode, mode, ret);
204 if (ret < 0) {
205 return retError(-ret);
206 } else {
207 files.push_back(std::move(file));
208 return retOK(files.size() - 1);
209 }
210}
211
214{
215 if (handle > files.size()) {
216 DPRINTF(Semihosting, "Semihosting SYS_CLOSE(%i): Illegal file\n");
217 return retError(EBADF);
218 }
219
220 std::unique_ptr<FileBase> &file = files[handle];
221 int64_t error = file->close();
222 DPRINTF(Semihosting, "Semihosting SYS_CLOSE(%i[%s]): %i\n", handle,
223 file->fileName(), error);
224 if (error < 0) {
225 return retError(-error);
226 } else {
227 // Zap the pointer and free the entry in the file table as
228 // well.
229 files[handle].reset();
230 return retOK(0);
231 }
232}
233
236{
237 const char c = portProxy(tc).read<char>(arg.addr);
238
239 DPRINTF(Semihosting, "Semihosting SYS_WRITEC('%c')\n", c);
240 std::cout.put(c);
241 std::cout.flush();
242
243 return retOK(0);
244}
245
248{
249 DPRINTF(Semihosting, "Semihosting SYS_WRITE0(...)\n");
250 PortProxy &proxy = portProxy(tc);
251 std::string str;
252 proxy.readString(str, arg.addr);
253 DDUMP(Semihosting, str.data(), str.size());
254 std::cout.write(str.c_str(), str.size());
255 std::cout.flush();
256
257 return retOK(0);
258}
259
262 ThreadContext *tc, Handle handle, Addr addr, size_t size)
263{
264 if (handle > files.size() || !files[handle])
265 return RetErrno(size, EBADF);
266
267 DPRINTF(Semihosting, "Semihosting SYS_WRITE(%x, %d)\n", addr, size);
268 std::vector<uint8_t> buffer(size);
269 portProxy(tc).readBlob(addr, buffer.data(), buffer.size());
270 DDUMP(Semihosting, buffer.data(), buffer.size());
271
272 int64_t ret = files[handle]->write(buffer.data(), buffer.size());
273 if (ret < 0) {
274 // No bytes written (we're returning the number of bytes not
275 // written)
276 return RetErrno(size, -ret);
277 } else {
278 // Return the number of bytes not written
279 return RetErrno(size - ret, 0);
280 }
281}
282
285 ThreadContext *tc, Handle handle, Addr addr, size_t size)
286{
287 if (handle > files.size() || !files[handle])
288 return RetErrno(size, EBADF);
289
290 std::vector<uint8_t> buffer(size);
291 int64_t ret = files[handle]->read(buffer.data(), buffer.size());
292 if (ret < 0) {
293 return RetErrno(size, -ret);
294 } else {
295 panic_if(ret > buffer.size(), "Read longer than buffer size.");
296
297 portProxy(tc).writeBlob(addr, buffer.data(), ret);
298
299 // Return the number of bytes not written
300 return retOK(size - ret);
301 }
302}
303
306{
307 return retOK((char)std::cin.get());
308}
309
312{
313 return retOK(status < 0 ? 1 : 0);
314}
315
318{
319 if (handle > files.size() || !files[handle])
320 return retError(EBADF);
321
322 int64_t ret = files[handle]->isTTY();
323 if (ret < 0) {
324 return retError(-ret);
325 } else {
326 return retOK(ret ? 1 : 0);
327 }
328}
329
332{
333 if (handle > files.size() || !files[handle])
334 return retError(EBADF);
335
336 int64_t ret = files[handle]->seek(pos);
337 if (ret < 0) {
338 return retError(-ret);
339 } else {
340 return retOK(0);
341 }
342}
343
346{
347 if (handle > files.size() || !files[handle])
348 return retError(EBADF);
349
350 int64_t ret = files[handle]->flen();
351 if (ret < 0) {
352 return retError(-ret);
353 } else {
354 return retOK(ret);
355 }
356}
357
360 ThreadContext *tc, Addr addr, uint64_t id, size_t size)
361{
362 std::string path = "";
363 int64_t unlink_call_ret = 0;
364
365 do {
366 path = simout.resolve(csprintf("%s.tmp%05i", name(), tmpNameIndex++));
367 // remove the (potentially existing) file of the given path
368 unlink_call_ret = unlink(path.c_str());
369 // if the file is busy, find another name
370 } while ((unlink_call_ret < 0) && (errno == EBUSY));
371
372 const size_t path_len = path.length();
373 if (path_len >= size)
374 return retError(ENOSPC);
375
376 portProxy(tc).writeBlob(addr, path.c_str(), path_len + 1);
377 return retOK(0);
378}
379
382 ThreadContext *tc, Addr name_base, size_t name_size)
383{
384 std::optional<std::string> fname = readString(tc, name_base, name_size);
385
386 if (!fname.has_value()) {
387 return retError(ERANGE);
388 } else if (remove(fname->c_str()) != 0) {
389 return retError(errno);
390 } else {
391 return retOK(0);
392 }
393}
394
397 size_t from_size, Addr to_addr, size_t to_size)
398{
399 std::optional<std::string> from = readString(tc, from_addr, from_size);
400 std::optional<std::string> to = readString(tc, to_addr, to_size);
401 if (!from.has_value() || !to.has_value()) {
402 return retError(ERANGE);
403 } else if (rename(from->c_str(), to->c_str()) != 0) {
404 return retError(errno);
405 } else {
406 return retOK(0);
407 }
408}
409
415
421
423BaseSemihosting::callSystem(ThreadContext *tc, Addr cmd_addr, size_t cmd_size)
424{
425 const std::optional<std::string> cmd = readString(tc, cmd_addr, cmd_size);
426 if (!cmd.has_value())
427 return retError(ERANGE);
428 warn("Semihosting: SYS_SYSTEM not implemented. Guest tried to run: %s\n",
429 *cmd);
430 return retError(EINVAL);
431}
432
435{
436 // Preserve errno by returning it in errno as well.
438}
439
442 ThreadContext *tc, Addr addr, InPlaceArg size_arg)
443{
444 PortProxy &proxy = portProxy(tc);
445 ByteOrder endian = byteOrder(tc);
446 size_t size = size_arg.read(tc, proxy, endian);
447
448 if (cmdLine.size() + 1 < size) {
449 proxy.writeBlob(addr, cmdLine.c_str(), cmdLine.size() + 1);
450 size_arg.write(tc, proxy, cmdLine.size(), endian);
451 return retOK(0);
452 } else {
453 return retError(0);
454 }
455}
456
457void
459 Addr &heap_base, Addr &heap_limit, Addr &stack_base, Addr &stack_limit)
460{
461 const memory::PhysicalMemory &phys = tc->getSystemPtr()->getPhysMem();
462 const AddrRangeList memories = phys.getConfAddrRanges();
463 fatal_if(memories.size() < 1, "No memories reported from System");
464 warn_if(memories.size() > 1,
465 "Multiple physical memory ranges available. "
466 "Using first range heap/stack.");
467 const AddrRange mem = *memories.begin();
468 const Addr mem_start = mem.start() + memReserve;
469 Addr mem_end = mem.end();
470
471 // Make sure that 32-bit guests can access their memory.
472 if (!aarch64) {
473 const Addr phys_max = (1ULL << 32) - 1;
474 panic_if(mem_start > phys_max,
475 "Physical memory out of range for a 32-bit guest.");
476 if (mem_end > phys_max) {
477 warn("Some physical memory out of range for a 32-bit guest.");
478 mem_end = phys_max;
479 }
480 }
481
482 fatal_if(mem_start + stackSize >= mem_end,
483 "Physical memory too small to fit desired stack and a heap.");
484
485 heap_base = mem_start;
486 heap_limit = mem_end - stackSize + 1;
487 stack_base = (mem_end + 1) & ~0x7ULL; // 8 byte stack alignment
488 stack_limit = heap_limit;
489
490 inform("Reporting heap/stack info to guest:\n"
491 "\tHeap base: 0x%x\n"
492 "\tHeap limit: 0x%x\n"
493 "\tStack base: 0x%x\n"
494 "\tStack limit: 0x%x\n",
495 heap_base, heap_limit, stack_base, stack_limit);
496}
497
500{
501 uint64_t heap_base, heap_limit, stack_base, stack_limit;
502 gatherHeapInfo(tc, false, heap_base, heap_limit, stack_base, stack_limit);
503
504 std::array<uint32_t, 4> block = {
505 {(uint32_t)heap_base, (uint32_t)heap_limit, (uint32_t)stack_base,
506 (uint32_t)stack_limit}};
507 portProxy(tc).write(block_addr, block, byteOrder(tc));
508
509 return retOK(0);
510}
511
514{
515 uint64_t heap_base, heap_limit, stack_base, stack_limit;
516 gatherHeapInfo(tc, true, heap_base, heap_limit, stack_base, stack_limit);
517
518 std::array<uint64_t, 4> block = {
519 {heap_base, heap_limit, stack_base, stack_limit}};
520 portProxy(tc).write(block_addr, block, byteOrder(tc));
521
522 return retOK(0);
523}
524
527{
528 semiExit(code.addr, 0);
529 return retOK(0);
530}
531
533BaseSemihosting::callExit64(ThreadContext *tc, uint64_t code, uint64_t subcode)
534{
535 semiExit(code, subcode);
536 return retOK(0);
537}
538
541 ThreadContext *tc, uint64_t code, uint64_t subcode)
542{
543 semiExit(code, subcode);
544 return retOK(0);
545}
546
547void
548BaseSemihosting::semiExit(uint64_t code, uint64_t subcode)
549{
550 auto it = exitCodes.find(code);
551 if (it != exitCodes.end()) {
552 exitSimLoop(it->second, subcode);
553 } else {
554 exitSimLoop(csprintf("semi:0x%x", code), subcode);
555 }
556}
557
561{
562 PortProxy &proxy = portProxy(tc);
563 ByteOrder endian = byteOrder(tc);
564 uint64_t tick = semiTick(curTick());
565
566 low.write(tc, proxy, tick, endian);
567 high.write(tc, proxy, tick >> 32, endian);
568
569 return retOK(0);
570}
571
574{
575 ticks.write(tc, portProxy(tc), semiTick(curTick()), byteOrder(tc));
576 return retOK(0);
577}
578
584
585FILE *
587 const char *stream_name, const std::string &name, const char *mode)
588{
589 auto it = stdioMap.find(name);
590 if (it == stdioMap.end()) {
591 FILE *f = fopen(name.c_str(), mode);
592 if (!f) {
593 fatal("Failed to open %s (%s): %s\n", stream_name, name,
594 strerror(errno));
595 }
596 return f;
597 } else {
598 return it->second;
599 }
600}
601
602std::unique_ptr<BaseSemihosting::FileBase>
604 BaseSemihosting &parent, const std::string &fname, const char *mode)
605{
606 std::unique_ptr<FileBase> file;
607 if (fname == ":semihosting-features") {
608 file.reset(new FileFeatures(parent, fname.c_str(), mode));
609 } else {
610 file.reset(new File(parent, fname.c_str(), mode));
611 }
612
613 return file;
614}
615
616std::unique_ptr<BaseSemihosting::FileBase>
618 BaseSemihosting &parent, CheckpointIn &cp, const std::string &sec)
619{
620 std::unique_ptr<FileBase> file;
621 ScopedCheckpointSection _sec(cp, sec);
622
623 // Was the file open when the checkpoint was created?
625 return file;
626
627 std::string fname, mode;
628 paramIn(cp, "name", fname);
629 paramIn(cp, "mode", mode);
630 file = create(parent, fname, mode.c_str());
631 assert(file);
632 file->unserialize(cp);
633
634 return file;
635}
636
637void
643
644void
646{
647 /* Unserialization of name and mode happens in
648 * BaseSemihosting::FileBase::create() */
649}
650
651int64_t
652BaseSemihosting::FileBase::read(uint8_t *buffer, uint64_t size)
653{
654 return -EINVAL;
655}
656
657int64_t
658BaseSemihosting::FileBase::write(const uint8_t *buffer, uint64_t size)
659{
660 return -EINVAL;
661}
662
663int64_t
665{
666 return -EINVAL;
667}
668
669int64_t
671{
672 return -EINVAL;
673}
674
676FileFeatures(BaseSemihosting &_parent, const char *_name, const char *_mode) :
677 FileBase(_parent, _name, _mode)
678{}
679
680int64_t
682{
683 return features.size();
684}
685
686int64_t
687BaseSemihosting::FileFeatures::read(uint8_t *buffer, uint64_t size)
688{
689 int64_t len = 0;
690
691 for (; len < size && pos < features.size(); pos++)
692 buffer[len++] = features[pos];
693
694 return len;
695}
696
697int64_t
699{
700 if (_pos < BaseSemihosting::features.size()) {
701 pos = _pos;
702 return 0;
703 } else {
704 return -ENXIO;
705 }
706}
707
708void
714
715void
721
723File(BaseSemihosting &_parent, const char *_name, const char *_perms) :
724 FileBase(_parent, _name, _perms), file(nullptr)
725{}
726
727BaseSemihosting::File::~
728File()
729{
730 if (file)
731 close();
732}
733
734int64_t
736{
737 panic_if(file, "Trying to open an already open file.\n");
738
739 if (_name == ":tt") {
740 if (mode[0] == 'r') {
741 file = parent.stdin;
742 } else if (mode[0] == 'w') {
743 file = parent.stdout;
744 } else if (mode[0] == 'a') {
745 file = parent.stderr;
746 } else {
747 warn("Unknown file mode for the ':tt' special file");
748 return -EINVAL;
749 }
750 } else {
751 std::string real_mode(this->mode);
752 // Avoid truncating the file if we are restoring from a
753 // checkpoint.
754 if (in_cpt && real_mode[0] == 'w')
755 real_mode[0] = 'a';
756
757 file = fopen(_name.c_str(), real_mode.c_str());
758 }
759
760 return file ? 0 : -errno;
761}
762
763int64_t
765{
766 panic_if(!file, "Trying to close an already closed file.\n");
767
768 if (needClose()) {
769 fclose(file);
770 }
771 file = nullptr;
772
773 return 0;
774}
775
776bool
778{
779 return file == parent.stdout || file == parent.stderr ||
780 file == parent.stdin;
781}
782
783int64_t
784BaseSemihosting::File::read(uint8_t *buffer, uint64_t size)
785{
786 panic_if(!file, "Trying to read from a closed file");
787
788 size_t ret = fread(buffer, 1, size, file);
789 if (ret == 0) {
790 // Error or EOF. Assume errors are due to invalid file
791 // operations (e.g., reading a write-only stream).
792 return ferror(file) ? -EINVAL : 0;
793 } else {
794 return ret;
795 }
796}
797
798int64_t
799BaseSemihosting::File::write(const uint8_t *buffer, uint64_t size)
800{
801 panic_if(!file, "Trying to write to a closed file");
802
803 size_t ret = fwrite(buffer, 1, size, file);
804 if (ret == 0) {
805 // Assume errors are due to invalid file operations (e.g.,
806 // writing a read-only stream).
807 return -EINVAL;
808 } else {
809 return ret;
810 }
811}
812
813int64_t
815{
816 panic_if(!file, "Trying to seek in a closed file");
817
818 errno = 0;
819 if (fseek(file, _pos, SEEK_SET) == 0)
820 return 0;
821 else
822 return -errno;
823}
824
825int64_t
827{
828 errno = 0;
829 long pos = ftell(file);
830 if (pos < 0)
831 return -errno;
832
833 if (fseek(file, 0, SEEK_END) != 0)
834 return -errno;
835
836 long len = ftell(file);
837 if (len < 0)
838 return -errno;
839
840 if (fseek(file, pos, SEEK_SET) != 0)
841 return -errno;
842
843 return len;
844}
845
846void
848{
850
851 if (!isTTY()) {
852 long pos = file ? ftell(file) : 0;
853 panic_if(pos < 0, "Failed to get file position.");
854 SERIALIZE_SCALAR(pos);
855 }
856}
857
858void
860{
862
863 if (openImpl(true) < 0) {
864 fatal("Failed to open file: %s", _name);
865 }
866
867 if (!isTTY()) {
868 long pos = 0;
870 if (fseek(file, pos, SEEK_SET) != 0) {
871 fatal("Failed seek to current position (%i) in '%s'", pos, _name);
872 }
873 }
874}
875
876std::ostream &
877operator<<(std::ostream &os, const BaseSemihosting::InPlaceArg &ipa)
878{
879 ccprintf(os, "[%#x-%#x)", ipa.addr, ipa.addr + ipa.size - 1);
880 return os;
881}
882
883} // namespace gem5
std::string error
#define DDUMP(x, data, count)
DPRINTF is a debugging trace facility that allows one to selectively enable tracing statements.
Definition trace.hh:203
#define DPRINTF(x,...)
Definition trace.hh:209
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.
virtual int64_t write(const uint8_t *buffer, uint64_t size)
Write data to file.
void serialize(CheckpointOut &cp) const override
Serialize an object.
virtual int64_t seek(uint64_t pos)
Seek to an absolute position in the file.
virtual int64_t read(uint8_t *buffer, uint64_t size)
Read data from file.
static std::unique_ptr< FileBase > create(BaseSemihosting &parent, const std::string &fname, const char *mode)
virtual int64_t flen()
Get the length of a file in bytes.
void unserialize(CheckpointIn &cp) override
Unserialize an object.
Implementation of the ':semihosting-features' magic file.
void unserialize(CheckpointIn &cp) override
Unserialize an object.
int64_t seek(uint64_t pos) override
Seek to an absolute position in the file.
FileFeatures(BaseSemihosting &_parent, const char *name, const char *mode)
int64_t flen() override
Get the length of a file in bytes.
int64_t read(uint8_t *buffer, uint64_t size) override
Read data from file.
void serialize(CheckpointOut &cp) const override
Serialize an object.
bool isTTY() const override
Check if a file corresponds to a TTY device.
int64_t close() override
Close the file.
void unserialize(CheckpointIn &cp) override
Unserialize an object.
File(BaseSemihosting &_parent, const char *name, const char *mode)
void serialize(CheckpointOut &cp) const override
Serialize an object.
int64_t read(uint8_t *buffer, uint64_t size) override
Read data from file.
int64_t flen() override
Get the length of a file in bytes.
int64_t seek(uint64_t pos) override
Seek to an absolute position in the file.
int64_t openImpl(bool unserialize)
int64_t write(const uint8_t *buffer, uint64_t size) override
Write data to file.
Semihosting for AArch32, AArch64, RISCV-32 and RISCV-64: https://github.com/ARM-software/abi-aa/blob/...
RetErrno callReadC(ThreadContext *tc)
RetErrno callElapsed32(ThreadContext *tc, InPlaceArg low, InPlaceArg high)
RetErrno callExit64(ThreadContext *tc, uint64_t code, uint64_t subcode)
static const std::map< uint64_t, const char * > exitCodes
RetErrno callFLen(ThreadContext *tc, Handle handle)
const std::string cmdLine
static const std::array< uint8_t, 5 > features
static FILE * getSTDIO(const char *stream_name, const std::string &name, const char *mode)
RetErrno callTickFreq(ThreadContext *tc)
std::pair< uint64_t, SemiErrno > RetErrno
virtual ByteOrder byteOrder(ThreadContext *tc) const =0
static const std::map< const std::string, FILE * > stdioMap
RetErrno callRename(ThreadContext *tc, Addr from_addr, size_t from_size, Addr to_addr, size_t to_size)
RetErrno callExitExtended(ThreadContext *tc, uint64_t code, uint64_t subcode)
RetErrno callTmpNam(ThreadContext *tc, Addr buffer, uint64_t id, size_t size)
RetErrno callSeek(ThreadContext *tc, Handle handle, uint64_t pos)
std::vector< std::unique_ptr< FileBase > > files
static const std::vector< const char * > fmodes
RetErrno callSystem(ThreadContext *tc, Addr cmd_addr, size_t cmd_size)
BaseSemihosting(const BaseSemihostingParams &p)
void unserialize(CheckpointIn &cp) override
Unserialize an object.
RetErrno callWrite(ThreadContext *tc, Handle handle, Addr buffer, size_t size)
RetErrno callOpen(ThreadContext *tc, const Addr name_base, int fmode, size_t name_size)
static RetErrno retError(SemiErrno e)
RetErrno callIsError(ThreadContext *tc, int64_t status)
void semiExit(uint64_t code, uint64_t subcode)
RetErrno callElapsed64(ThreadContext *tc, InPlaceArg ticks)
RetErrno callRead(ThreadContext *tc, Handle handle, Addr buffer, size_t size)
const time_t timeBase
Base time when the simulation started.
RetErrno callExit32(ThreadContext *tc, InPlaceArg code)
void serialize(CheckpointOut &cp) const override
Serialize an object.
virtual PortProxy & portProxy(ThreadContext *tc) const =0
static RetErrno retOK(uint64_t r)
void gatherHeapInfo(ThreadContext *tc, bool aarch64, Addr &heap_base, Addr &heap_limit, Addr &stack_base, Addr &stack_limit)
RetErrno callGetCmdLine(ThreadContext *tc, Addr addr, InPlaceArg size_arg)
RetErrno callHeapInfo32(ThreadContext *tc, Addr block_addr)
RetErrno callClock(ThreadContext *tc)
std::optional< std::string > readString(ThreadContext *tc, Addr ptr, size_t len)
RetErrno callRemove(ThreadContext *tc, Addr name_base, size_t name_size)
RetErrno callHeapInfo64(ThreadContext *tc, Addr block_addr)
uint64_t semiTick(Tick tick) const
RetErrno callIsTTY(ThreadContext *tc, Handle handle)
RetErrno callWriteC(ThreadContext *tc, InPlaceArg c)
RetErrno callErrno(ThreadContext *tc)
RetErrno callTime(ThreadContext *tc)
RetErrno callWrite0(ThreadContext *tc, InPlaceArg str)
RetErrno callClose(ThreadContext *tc, Handle handle)
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
void readBlob(Addr addr, void *p, uint64_t size) const
Higher level interfaces based on the above.
T read(Addr address) const
Read sizeof(T) bytes from address and return as object T.
void writeBlob(Addr addr, const void *p, uint64_t size) const
Same as tryWriteBlob, but insists on success.
void write(Addr address, const T &data) const
Write object T to address.
void readString(std::string &str, Addr addr) const
Same as tryReadString, but insists on success.
static std::stack< std::string > path
Definition serialize.hh:315
Abstract superclass for simulation objects.
memory::PhysicalMemory & getPhysMem()
Get a pointer to access the physical memory of the system.
Definition system.hh:342
ThreadContext is the external interface to all thread state for anything outside of the CPU.
virtual System * getSystemPtr()=0
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
STL vector class.
Definition stl.hh:37
#define fatal_if(cond,...)
Conditional fatal macro that checks the supplied condition and only causes a fatal error if the condi...
Definition logging.hh:236
#define fatal(...)
This implements a cprintf based fatal() function.
Definition logging.hh:200
#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
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:203
#define warn(...)
Definition logging.hh:256
#define warn_if(cond,...)
Conditional warning macro that checks the supplied condition and only prints a warning if the conditi...
Definition logging.hh:283
#define inform(...)
Definition logging.hh:257
Bitfield< 18, 16 > len
Bitfield< 4, 0 > mode
Definition misc_types.hh:74
Bitfield< 5 > t
Definition misc_types.hh:71
Bitfield< 7 > i
Definition misc_types.hh:67
Bitfield< 5, 0 > status
Bitfield< 29 > c
Definition misc_types.hh:53
Bitfield< 6 > f
Definition misc_types.hh:68
Bitfield< 34 > aarch64
Definition types.hh:81
Bitfield< 0 > p
Bitfield< 25, 21 > to
Definition types.hh:96
Bitfield< 32 > tm
Definition misc.hh:112
Bitfield< 17 > os
Definition misc.hh:838
Bitfield< 3 > addr
Definition types.hh:84
double s
These variables equal the number of ticks in the unit of time they're named after in a double.
Definition core.cc:51
Tick Frequency
The simulated frequency of curTick(). (In ticks per second)
Definition core.cc:47
Copyright (c) 2024 Arm Limited All rights reserved.
Definition binary32.hh:36
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
void paramIn(CheckpointIn &cp, const std::string &name, ExtMachInst &machInst)
Definition types.cc:72
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
std::ostream & operator<<(std::ostream &os, const BaseSemihosting::InPlaceArg &ipa)
std::string csprintf(const char *format, const Args &...args)
Definition cprintf.hh:161
void ccprintf(cp::Print &print)
Definition cprintf.hh:130
#define UNSERIALIZE_SCALAR(scalar)
Definition serialize.hh:575
#define SERIALIZE_SCALAR(scalar)
Definition serialize.hh:568
void write(ThreadContext *tc, PortProxy &proxy, uint64_t val, ByteOrder endian)
uint64_t read(ThreadContext *tc, PortProxy &proxy, ByteOrder endian)
bool_vector8 mem[]
Definition reset_stim.h:43
const std::string & name()
Definition trace.cc:48

Generated on Mon Jan 13 2025 04:28:28 for gem5 by doxygen 1.9.8