gem5 v24.0.0.0
Loading...
Searching...
No Matches
semihosting.hh
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#ifndef __ARCH_GENERIC_SEMIHOSTING_HH__
39#define __ARCH_GENERIC_SEMIHOSTING_HH__
40
41#include <cstdio>
42#include <functional>
43#include <map>
44#include <memory>
45#include <optional>
46#include <utility>
47#include <vector>
48
49#include "base/time.hh"
50#include "cpu/thread_context.hh"
51#include "mem/port_proxy.hh"
52#include "sim/core.hh"
53#include "sim/guest_abi.hh"
54#include "sim/sim_object.hh"
55
56namespace gem5
57{
58
59struct BaseSemihostingParams;
60class SerialDevice;
61
81{
82 virtual PortProxy &portProxy(ThreadContext *tc) const = 0;
83 virtual ByteOrder byteOrder(ThreadContext *tc) const = 0;
84
85 public:
86 struct AbiBase
87 {
88 template <typename Arg, class BaseSemihostingImpl>
90 {
91 private:
93 ByteOrder endian;
94
95 public:
96 StateBase(const ThreadContext *tc, Addr arg_pointer,
97 std::function<ByteOrder(const ThreadContext *tc)>
98 getByteOrder) :
99 argPointer(arg_pointer), endian(getByteOrder(tc))
100 {}
101
102 /*
103 * These two methods are used to both read an argument or its
104 * address, and to move position on to the next location. Normally
105 * State would be more passive, but since it behaves almost the
106 * same no matter what the argument type is we can simplify and
107 * consolidate a little bit by centralizing these methods.
108 */
109
110 // Return the address of an argument slot and move past it.
111 Addr
113 {
115 argPointer += sizeof(Arg);
116 return addr;
117 }
118
119 // Read the value in an argument slot and move past it.
120 Arg
122 {
123 Arg arg = BaseSemihostingImpl::portProxyImpl(tc)
124 .template read<Arg>(argPointer, endian);
125 argPointer += sizeof(Arg);
126 return arg;
127 }
128
129 using ArgType = Arg;
130 };
131 };
132
133 // Use this argument type when you need to modify an argument in place.
134 // This will give you the address of the argument itself and the size of
135 // each argument slot, rather than the actual value of the argument.
137 {
139 size_t size;
140
141 InPlaceArg(Addr _addr, size_t _size) : addr(_addr), size(_size) {}
142
143 // A helper function to read the argument since the guest ABI mechanism
144 // didn't do that for us.
145 uint64_t
146 read(ThreadContext *tc, PortProxy &proxy, ByteOrder endian)
147 {
148 if (size == 8)
149 return proxy.read<uint64_t>(addr, endian);
150 else if (size == 4)
151 return proxy.read<uint32_t>(addr, endian);
152 else
153 panic("Unexpected semihosting argument size %d.", size);
154 }
155
156 // A helper function to write to the argument's slot in the params.
157 void
158 write(ThreadContext *tc, PortProxy &proxy, uint64_t val,
159 ByteOrder endian)
160 {
161 if (size == 8)
162 proxy.write<uint64_t>(addr, val, endian);
163 else if (size == 4)
164 proxy.write<uint32_t>(addr, val, endian);
165 else
166 panic("Unexpected semihosting argument size %d.", size);
167 }
168 };
169
170 protected:
171 explicit BaseSemihosting(const BaseSemihostingParams &p);
172
173 public: // SimObject and related interfaces
174 void serialize(CheckpointOut &cp) const override;
175 void unserialize(CheckpointIn &cp) override;
176
177 protected: // Configuration
178 const std::string cmdLine;
181
186 const time_t timeBase;
187
189 const unsigned tickShift;
190
191 protected: // Internal state
192 typedef uint64_t SemiErrno;
194
195 protected: // File IO
209 class FileBase : public Serializable
210 {
211 public:
212 FileBase(BaseSemihosting &_parent, const char *name,
213 const char *_mode) : parent(_parent), _name(name), mode(_mode)
214 {}
215 virtual ~FileBase(){};
216
217 FileBase() = delete;
218 FileBase(FileBase &) = delete;
219
220 static std::unique_ptr<FileBase> create(BaseSemihosting &parent,
221 const std::string &fname, const char *mode);
222 static std::unique_ptr<FileBase> create(BaseSemihosting &parent,
223 CheckpointIn &cp, const std::string &sec);
224
225 void serialize(CheckpointOut &cp) const override;
226 void unserialize(CheckpointIn &cp) override;
227
228 const std::string &
230 {
231 return _name;
232 }
233
234 public:
250 virtual int64_t
252 {
253 return 0;
254 }
255
261 virtual int64_t
263 {
264 return 0;
265 }
266
272 virtual bool
273 isTTY() const
274 {
275 return false;
276 }
277
283 virtual int64_t read(uint8_t *buffer, uint64_t size);
284
290 virtual int64_t write(const uint8_t *buffer, uint64_t size);
291
298 virtual int64_t seek(uint64_t pos);
299
305 virtual int64_t flen();
306
309 protected:
311 std::string _name;
312 std::string mode;
313 };
314
316 class FileFeatures : public FileBase
317 {
318 public:
320 BaseSemihosting &_parent, const char *name, const char *mode);
321
322 void serialize(CheckpointOut &cp) const override;
323 void unserialize(CheckpointIn &cp) override;
324
325 int64_t read(uint8_t *buffer, uint64_t size) override;
326 int64_t seek(uint64_t pos) override;
327 int64_t flen() override;
328
329 protected:
330 size_t pos = 0;
331 };
332
333 class File : public FileBase
334 {
335 public:
336 File(BaseSemihosting &_parent, const char *name, const char *mode);
337 ~File();
338
339 void serialize(CheckpointOut &cp) const override;
340 void unserialize(CheckpointIn &cp) override;
341
342 int64_t
343 open() override
344 {
345 return openImpl(false);
346 }
347 int64_t close() override;
348 bool isTTY() const override;
349 int64_t read(uint8_t *buffer, uint64_t size) override;
350 int64_t write(const uint8_t *buffer, uint64_t size) override;
351 int64_t seek(uint64_t pos) override;
352 int64_t flen() override;
353
354 protected:
355 int64_t openImpl(bool unserialize);
356 bool
357 needClose() const
358 {
359 return !isTTY();
360 }
361
362 FILE *file;
363 };
364
365 std::string filesRootDir;
367 using Handle = size_t;
368 FILE *stdin;
369 FILE *stdout;
370 FILE *stderr;
371
372 protected: // Helper functions
373 unsigned
375 {
377 return msb > 31 ? msb - 31 : 0;
378 }
379 uint64_t
380 semiTick(Tick tick) const
381 {
382 return tick >> tickShift;
383 }
384 void semiExit(uint64_t code, uint64_t subcode);
385
386 std::optional<std::string> readString(ThreadContext *tc,
387 Addr ptr, size_t len);
388
389 public:
391
392 protected:
393 static RetErrno
395 {
396 return RetErrno((uint64_t)-1, e);
397 }
398
399 static RetErrno
400 retOK(uint64_t r)
401 {
402 return RetErrno(r, 0);
403 }
404
412 template <typename Semihosting, typename Abi32, typename Abi64>
414 {
416 const char *name;
417
418 // A type for member functions implementing semihosting calls.
419 template <typename Impl, typename... Args>
420 using Implementation = RetErrno (Impl::*)(
421 ThreadContext *tc, Args... args);
422
423 // Since guest ABI doesn't know how to call member function pointers,
424 // this template builds a wrapper that takes care of that.
425 template <typename SemiImpl, typename... Args>
426 static inline std::function<RetErrno(ThreadContext *tc, Args... args)>
428 {
429 return [sh, impl](ThreadContext *tc, Args... args) {
430 return (sh->*impl)(tc, args...);
431 };
432 }
433
434 // A type for functions which dispatch semihosting calls through the
435 // guest ABI mechanism.
437 std::function<RetErrno(Semihosting *sh, ThreadContext *tc)>;
438 using Dumper = std::function<std::string(ThreadContext *tc)>;
439
440 // Dispatchers for 32 and 64 bits.
443
444 // Dumpers which print semihosting calls and their arguments.
447
448 // A function which builds a dispatcher for a semihosting call.
449 template <typename Abi, typename SemiImpl, typename... Args>
450 static inline Dispatcher
452 {
453 // This lambda is the dispatcher we're building.
454 return [impl](SemiImpl *sh, ThreadContext *tc) {
455 auto wrapper = wrapImpl<SemiImpl, Args...>(sh, impl);
456 return invokeSimcall<Abi>(tc, wrapper);
457 };
458 }
459
460 // A function which builds a dumper for a semihosting call.
461 template <typename Abi, typename SemiImpl, typename... Args>
462 static inline Dumper
464 {
465 // This lambda is the dumper we're building.
466 return [name](ThreadContext *tc) -> std::string {
467 return dumpSimcall<Abi, RetErrno, Args...>(name, tc);
468 };
469 }
470
471 // When there's one implementation, use it for both 32 and 64 bits.
472 template <typename SemiImpl, typename... Args>
474 const char *_name, Implementation<SemiImpl, Args...> common) :
475 name(_name), call32(buildDispatcher<Abi32>(common)),
476 call64(buildDispatcher<Abi64>(common)),
477 dump32(buildDumper<Abi32>(_name, common)),
478 dump64(buildDumper<Abi64>(_name, common))
479 {}
480
481 // When there are two, use one for 32 bits and one for 64 bits.
482 template <typename SemiImpl, typename... Args32, typename... Args64>
483 SemiCallBase(const char *_name,
486 name(_name), call32(buildDispatcher<Abi32, SemiImpl>(impl32)),
487 call64(buildDispatcher<Abi64, SemiImpl>(impl64)),
488 dump32(buildDumper<Abi32, SemiImpl>(_name, impl32)),
489 dump64(buildDumper<Abi64, SemiImpl>(_name, impl64))
490 {}
491 };
492
493 public:
494 RetErrno callOpen(ThreadContext *tc, const Addr name_base, int fmode,
495 size_t name_size);
497 RetErrno callWriteC(ThreadContext *tc, InPlaceArg c);
498 RetErrno callWrite0(ThreadContext *tc, InPlaceArg str);
500 ThreadContext *tc, Handle handle, Addr buffer, size_t size);
502 ThreadContext *tc, Handle handle, Addr buffer, size_t size);
506 RetErrno callSeek(ThreadContext *tc, Handle handle, uint64_t pos);
509 ThreadContext *tc, Addr buffer, uint64_t id, size_t size);
510 RetErrno callRemove(ThreadContext *tc, Addr name_base, size_t name_size);
511 RetErrno callRename(ThreadContext *tc, Addr from_addr, size_t from_size,
512 Addr to_addr, size_t to_size);
515 RetErrno callSystem(ThreadContext *tc, Addr cmd_addr, size_t cmd_size);
517 RetErrno callGetCmdLine(ThreadContext *tc, Addr addr, InPlaceArg size_arg);
518
519 void gatherHeapInfo(ThreadContext *tc, bool aarch64, Addr &heap_base,
520 Addr &heap_limit, Addr &stack_base, Addr &stack_limit);
521 RetErrno callHeapInfo32(ThreadContext *tc, Addr block_addr);
522 RetErrno callHeapInfo64(ThreadContext *tc, Addr block_addr);
523 RetErrno callExit32(ThreadContext *tc, InPlaceArg code);
524 RetErrno callExit64(ThreadContext *tc, uint64_t code, uint64_t subcode);
526 ThreadContext *tc, uint64_t code, uint64_t subcode);
527
528 RetErrno callElapsed32(ThreadContext *tc, InPlaceArg low, InPlaceArg high);
529 RetErrno callElapsed64(ThreadContext *tc, InPlaceArg ticks);
531
532 template <typename Abi>
533 void
534 unrecognizedCall(ThreadContext *tc, const char *format, uint64_t op)
535 {
536 warn(format, op);
537 std::function<RetErrno(ThreadContext * tc)> retErr =
538 [](ThreadContext *tc) { return retError(EINVAL); };
539 invokeSimcall<Abi>(tc, retErr);
540 }
541
542 static FILE *getSTDIO(const char *stream_name, const std::string &name,
543 const char *mode);
544
546 static const std::map<uint64_t, const char *> exitCodes;
547 static const std::array<uint8_t, 5> features;
548 static const std::map<const std::string, FILE *> stdioMap;
549
550 // used in callTmpNam() to deterministically generate a temp filename
551 uint16_t tmpNameIndex = 0;
552};
553
554std::ostream &operator<<(
555 std::ostream &os, const BaseSemihosting::InPlaceArg &ipa);
556
557} // namespace gem5
558
559#endif // __ARCH_GENERIC_SEMIHOSTING_HH__
StateBase(const ThreadContext *tc, Addr arg_pointer, std::function< ByteOrder(const ThreadContext *tc)> getByteOrder)
Internal state for open files.
virtual int64_t write(const uint8_t *buffer, uint64_t size)
Write data to file.
virtual int64_t close()
Close the 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 bool isTTY() const
Check if a file corresponds to a TTY device.
FileBase(BaseSemihosting &_parent, const char *name, const char *_mode)
const std::string & fileName()
virtual int64_t flen()
Get the length of a file in bytes.
void unserialize(CheckpointIn &cp) override
Unserialize an object.
virtual int64_t open()
Open the the file.
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.
int64_t open() override
Open the the file.
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)
unsigned calcTickShift() const
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
void unrecognizedCall(ThreadContext *tc, const char *format, uint64_t op)
const unsigned tickShift
Number of bits to right shift gem5 ticks to fit in a uint32_t.
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
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.
void write(Addr address, const T &data) const
Write object T to address.
Basic support for object serialization.
Definition serialize.hh:170
Abstract superclass for simulation objects.
ThreadContext is the external interface to all thread state for anything outside of the CPU.
STL pair class.
Definition stl.hh:58
STL vector class.
Definition stl.hh:37
constexpr int findMsbSet(uint64_t val)
Returns the bit position of the MSB that is set in the input.
Definition bitfield.hh:279
#define panic(...)
This implements a cprintf based panic() function.
Definition logging.hh:188
#define warn(...)
Definition logging.hh:256
Bitfield< 18, 16 > len
Bitfield< 4, 0 > mode
Definition misc_types.hh:74
Bitfield< 8, 7 > sh
Bitfield< 9 > e
Definition misc_types.hh:65
Bitfield< 31, 29 > format
Bitfield< 5, 0 > status
Bitfield< 29 > c
Definition misc_types.hh:53
Bitfield< 34 > aarch64
Definition types.hh:81
Bitfield< 19, 16 > impl
Bitfield< 0 > p
Bitfield< 17 > os
Definition misc.hh:838
Bitfield< 4 > op
Definition types.hh:83
Bitfield< 63 > val
Definition misc.hh:804
Bitfield< 3 > addr
Definition types.hh:84
Tick Frequency
The simulated frequency of curTick(). (In ticks per second)
Definition core.cc:47
Copyright (c) 2024 - Pranith Kumar Copyright (c) 2020 Inria All rights reserved.
Definition binary32.hh:36
std::string dumpSimcall(std::string name, ThreadContext *tc, std::function< Ret(ThreadContext *, Args...)> target=std::function< Ret(ThreadContext *, Args...)>())
Definition guest_abi.hh:111
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
uint64_t Tick
Tick count type.
Definition types.hh:58
Ret invokeSimcall(ThreadContext *tc, std::function< Ret(ThreadContext *, Args...)> target)
Definition guest_abi.hh:50
static std::ostream & operator<<(std::ostream &os, const DummyMatRegContainer &d)
Definition matrix.hh:564
PortProxy Object Declaration.
InPlaceArg(Addr _addr, size_t _size)
void write(ThreadContext *tc, PortProxy &proxy, uint64_t val, ByteOrder endian)
uint64_t read(ThreadContext *tc, PortProxy &proxy, ByteOrder endian)
Semihosting call information structure.
std::function< RetErrno(Semihosting *sh, ThreadContext *tc)> Dispatcher
static Dispatcher buildDispatcher(Implementation< SemiImpl, Args... > impl)
static std::function< RetErrno(ThreadContext *tc, Args... args)> wrapImpl(SemiImpl *sh, Implementation< SemiImpl, Args... > impl)
RetErrno(Impl::*)( ThreadContext *tc, Args... args) Implementation
SemiCallBase(const char *_name, Implementation< SemiImpl, Args32... > impl32, Implementation< SemiImpl, Args64... > impl64)
std::function< std::string(ThreadContext *tc)> Dumper
static Dumper buildDumper(const char *name, Implementation< SemiImpl, Args... > impl)
SemiCallBase(const char *_name, Implementation< SemiImpl, Args... > common)

Generated on Tue Jun 18 2024 16:23:57 for gem5 by doxygen 1.11.0