semihosting.hh revision 12533:a5b047f55eb6
112837Sgabeblack@google.com/*
212837Sgabeblack@google.com * Copyright (c) 2018 ARM Limited
312837Sgabeblack@google.com * All rights reserved
412837Sgabeblack@google.com *
512837Sgabeblack@google.com * The license below extends only to copyright in the software and shall
612837Sgabeblack@google.com * not be construed as granting a license to any other intellectual
712837Sgabeblack@google.com * property including but not limited to intellectual property relating
812837Sgabeblack@google.com * to a hardware implementation of the functionality of the software
912837Sgabeblack@google.com * licensed hereunder.  You may use the software subject to the license
1012837Sgabeblack@google.com * terms below provided that you ensure that this notice is replicated
1112837Sgabeblack@google.com * unmodified and in its entirety in all distributions of the software,
1212837Sgabeblack@google.com * modified or unmodified, in source code or in binary form.
1312837Sgabeblack@google.com *
1412837Sgabeblack@google.com * Redistribution and use in source and binary forms, with or without
1512837Sgabeblack@google.com * modification, are permitted provided that the following conditions are
1612837Sgabeblack@google.com * met: redistributions of source code must retain the above copyright
1712837Sgabeblack@google.com * notice, this list of conditions and the following disclaimer;
1812837Sgabeblack@google.com * redistributions in binary form must reproduce the above copyright
1912837Sgabeblack@google.com * notice, this list of conditions and the following disclaimer in the
2012837Sgabeblack@google.com * documentation and/or other materials provided with the distribution;
2112837Sgabeblack@google.com * neither the name of the copyright holders nor the names of its
2212837Sgabeblack@google.com * contributors may be used to endorse or promote products derived from
2312837Sgabeblack@google.com * this software without specific prior written permission.
2412837Sgabeblack@google.com *
2512837Sgabeblack@google.com * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
2612837Sgabeblack@google.com * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
2712837Sgabeblack@google.com * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
2812837Sgabeblack@google.com * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
2912837Sgabeblack@google.com * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
3012837Sgabeblack@google.com * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
3112837Sgabeblack@google.com * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
3212862Sgabeblack@google.com * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
3312837Sgabeblack@google.com * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
3412862Sgabeblack@google.com * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
3512837Sgabeblack@google.com * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
3612862Sgabeblack@google.com *
3712837Sgabeblack@google.com * Authors: Andreas Sandberg
3812837Sgabeblack@google.com */
3912861Sgabeblack@google.com#ifndef __ARCH_ARM_SEMIHOSTING_HH__
4012837Sgabeblack@google.com#define __ARCH_ARM_SEMIHOSTING_HH__
4112837Sgabeblack@google.com
4212837Sgabeblack@google.com#include <cstdio>
4312837Sgabeblack@google.com#include <map>
4412837Sgabeblack@google.com#include <memory>
4512837Sgabeblack@google.com#include <utility>
4612837Sgabeblack@google.com#include <vector>
4712837Sgabeblack@google.com
4812837Sgabeblack@google.com#include "sim/sim_object.hh"
4912837Sgabeblack@google.com
5012837Sgabeblack@google.comstruct ArmSemihostingParams;
5112837Sgabeblack@google.comclass PortProxy;
5212837Sgabeblack@google.comclass SerialDevice;
5312837Sgabeblack@google.comclass ThreadContext;
5412837Sgabeblack@google.com
5512837Sgabeblack@google.com/**
5612837Sgabeblack@google.com * Semihosting for AArch32 and AArch64
5712837Sgabeblack@google.com *
5812837Sgabeblack@google.com * This class implements the Arm semihosting interface. This interface
5912837Sgabeblack@google.com * allows baremetal code access service, such as IO, from the
6012837Sgabeblack@google.com * simulator. It is conceptually a simplified version of gem5's more
6112837Sgabeblack@google.com * general syscall emulation mode.
6212837Sgabeblack@google.com *
6312862Sgabeblack@google.com * Exits calls (SYS_EXIT, SYS_EXIT_EXTENDED) from the guest get
6412862Sgabeblack@google.com * translated into simualtion exits. Well-known exit codes are
6512862Sgabeblack@google.com * translated to messages on the form 'semi:ADP_.*' while unknown
6612862Sgabeblack@google.com * codes are returned in hex ('semi:0x..'). The subcode is reported in
6712862Sgabeblack@google.com * the gem5 exit event.
6812862Sgabeblack@google.com */
6912862Sgabeblack@google.comclass ArmSemihosting : public SimObject
7012862Sgabeblack@google.com{
7112862Sgabeblack@google.com  public:
7212862Sgabeblack@google.com    ArmSemihosting(const ArmSemihostingParams *p);
7312862Sgabeblack@google.com
7412837Sgabeblack@google.com    /** Perform an Arm Semihosting call from aarch64 code. */
7512837Sgabeblack@google.com    uint64_t call64(ThreadContext *tc, uint32_t op, uint64_t param);
7612837Sgabeblack@google.com    /** Perform an Arm Semihosting call from aarch32 code. */
7712837Sgabeblack@google.com    uint32_t call32(ThreadContext *tc, uint32_t op, uint32_t param);
7812837Sgabeblack@google.com
7912837Sgabeblack@google.com  public: // SimObject and related interfaces
8012837Sgabeblack@google.com    void serialize(CheckpointOut &cp) const override;
8112837Sgabeblack@google.com    void unserialize(CheckpointIn &cp) override;
8212837Sgabeblack@google.com
8312837Sgabeblack@google.com  protected: // Configuration
8412837Sgabeblack@google.com    const std::string cmdLine;
8512837Sgabeblack@google.com    const Addr memReserve;
8612837Sgabeblack@google.com    const Addr stackSize;
8712837Sgabeblack@google.com
8812837Sgabeblack@google.com    /**
8912837Sgabeblack@google.com     * Base time when the simulation started. This is used to
9012837Sgabeblack@google.com     * calculate the time of date when the guest call SYS_TIME.
9112837Sgabeblack@google.com     */
9212837Sgabeblack@google.com    const time_t timeBase;
9312837Sgabeblack@google.com
9412837Sgabeblack@google.com    /** Number of bits to right shift gem5 ticks to fit in a uint32_t */
9512837Sgabeblack@google.com    const unsigned tickShift;
9612837Sgabeblack@google.com
9712837Sgabeblack@google.com  protected: // Internal state
9812837Sgabeblack@google.com    typedef uint64_t SemiErrno;
9912837Sgabeblack@google.com    SemiErrno semiErrno;
10012837Sgabeblack@google.com
10112837Sgabeblack@google.com  protected: // File IO
10212837Sgabeblack@google.com    /**
10312837Sgabeblack@google.com     * Internal state for open files
10412837Sgabeblack@google.com     *
10512837Sgabeblack@google.com     * This class describes the internal state of a file opened
10612837Sgabeblack@google.com     * through the semihosting interface.
10712837Sgabeblack@google.com     *
10812837Sgabeblack@google.com     * A file instance is normally created using one of the
10912837Sgabeblack@google.com     * ArmSemihosting::FileBase::create() factory methods. These
11012837Sgabeblack@google.com     * methods handle some the magic file names in the Arm Semihosting
11112862Sgabeblack@google.com     * specification and instantiate the right implementation. For the
11212837Sgabeblack@google.com     * same, when unserializing a checkpoint, the create method must
11312837Sgabeblack@google.com     * be used to unserialize a new instance of a file descriptor.
11412837Sgabeblack@google.com     */
11512837Sgabeblack@google.com    class FileBase : public Serializable
11612837Sgabeblack@google.com    {
11712837Sgabeblack@google.com      public:
11812837Sgabeblack@google.com        FileBase(ArmSemihosting &_parent, const char *name, const char *_mode)
11912837Sgabeblack@google.com            : parent(_parent), _name(name), mode(_mode) {}
12012837Sgabeblack@google.com        virtual ~FileBase() {};
12112837Sgabeblack@google.com
12212837Sgabeblack@google.com        FileBase() = delete;
12312837Sgabeblack@google.com        FileBase(FileBase &) = delete;
12412861Sgabeblack@google.com
12512861Sgabeblack@google.com        static std::unique_ptr<FileBase> create(
12612861Sgabeblack@google.com            ArmSemihosting &parent, const std::string &fname,
12712862Sgabeblack@google.com            const char *mode);
12812862Sgabeblack@google.com        static std::unique_ptr<FileBase> create(
12912862Sgabeblack@google.com            ArmSemihosting &parent, CheckpointIn &cp, const std::string &sec);
13012861Sgabeblack@google.com
13112861Sgabeblack@google.com        void serialize(CheckpointOut &cp) const override;
13212837Sgabeblack@google.com        void unserialize(CheckpointIn &cp) override;
13312837Sgabeblack@google.com
13412837Sgabeblack@google.com        const std::string &fileName() { return _name; }
13512837Sgabeblack@google.com
13612837Sgabeblack@google.com      public:
13712837Sgabeblack@google.com        /** @{
13812837Sgabeblack@google.com         * Semihosting file IO interfaces
13912837Sgabeblack@google.com         *
14012837Sgabeblack@google.com         * These interfaces implement common IO functionality in the
14112837Sgabeblack@google.com         * Semihosting interface.
14212837Sgabeblack@google.com         *
14312837Sgabeblack@google.com         * All functions return a negative value that corresponds to a
14412837Sgabeblack@google.com         * UNIX errno value when they fail and >=0 on success.
14512837Sgabeblack@google.com         */
14612860Sgabeblack@google.com
14712860Sgabeblack@google.com        /**
14812860Sgabeblack@google.com         * Open the the file.
14912862Sgabeblack@google.com         *
15012862Sgabeblack@google.com         * @return <0 on error (-errno), 0 on success.
15112862Sgabeblack@google.com         */
15212862Sgabeblack@google.com        virtual int64_t open() { return 0; }
15312862Sgabeblack@google.com
15412860Sgabeblack@google.com        /**
15512860Sgabeblack@google.com         * Close the file.
15612860Sgabeblack@google.com         *
15712860Sgabeblack@google.com         * @return <0 on error (-errno), 0 on success.
15812860Sgabeblack@google.com         */
15912860Sgabeblack@google.com        virtual int64_t close() { return 0; }
16012860Sgabeblack@google.com
16112860Sgabeblack@google.com        /**
16212860Sgabeblack@google.com         * Check if a file corresponds to a TTY device.
16312860Sgabeblack@google.com         *
16412860Sgabeblack@google.com         * @return True if the file is a TTY, false otherwise.
16512862Sgabeblack@google.com         */
16612862Sgabeblack@google.com        virtual bool isTTY() const { return false; }
16712862Sgabeblack@google.com
16812862Sgabeblack@google.com        /**
16912862Sgabeblack@google.com         * Read data from file.
17012862Sgabeblack@google.com         *
17112860Sgabeblack@google.com         * @return <0 on error (-errno), bytes read on success (0 for EOF).
17212860Sgabeblack@google.com         */
17312860Sgabeblack@google.com        virtual int64_t read(uint8_t *buffer, uint64_t size);
17412860Sgabeblack@google.com
17512860Sgabeblack@google.com        /**
17612861Sgabeblack@google.com         * Write data to file.
17712861Sgabeblack@google.com         *
17812861Sgabeblack@google.com         * @return <0 on error (-errno), bytes written on success.
17912861Sgabeblack@google.com         */
18012861Sgabeblack@google.com        virtual int64_t write(const uint8_t *buffer, uint64_t size);
18112861Sgabeblack@google.com
18212860Sgabeblack@google.com        /**
18312860Sgabeblack@google.com         * Seek to an absolute position in the file.
18412860Sgabeblack@google.com         *
18512860Sgabeblack@google.com         * @param pos Byte offset from start of file.
18612860Sgabeblack@google.com         * @return <0 on error (-errno), 0 on success.
18712861Sgabeblack@google.com         */
18812860Sgabeblack@google.com        virtual int64_t seek(uint64_t pos);
18912860Sgabeblack@google.com
19012860Sgabeblack@google.com        /**
19112860Sgabeblack@google.com         * Get the length of a file in bytes.
19212860Sgabeblack@google.com         *
19312860Sgabeblack@google.com         * @return <0 on error (-errno), length on success
19412860Sgabeblack@google.com         */
19512860Sgabeblack@google.com        virtual int64_t flen();
19612860Sgabeblack@google.com
19712860Sgabeblack@google.com        /** @} */
19812860Sgabeblack@google.com
19912860Sgabeblack@google.com      protected:
20012860Sgabeblack@google.com        ArmSemihosting &parent;
20112860Sgabeblack@google.com        std::string _name;
20212860Sgabeblack@google.com        std::string mode;
20312860Sgabeblack@google.com    };
20412860Sgabeblack@google.com
20512860Sgabeblack@google.com    /** Implementation of the ':semihosting-features' magic file. */
20612861Sgabeblack@google.com    class FileFeatures : public FileBase
20712860Sgabeblack@google.com    {
20812860Sgabeblack@google.com      public:
20912860Sgabeblack@google.com        FileFeatures(ArmSemihosting &_parent,
21012860Sgabeblack@google.com                     const char *name, const char *mode);
21112860Sgabeblack@google.com
21212861Sgabeblack@google.com        void serialize(CheckpointOut &cp) const override;
21312860Sgabeblack@google.com        void unserialize(CheckpointIn &cp) override;
21412860Sgabeblack@google.com
21512860Sgabeblack@google.com        int64_t read(uint8_t *buffer, uint64_t size) override;
21612860Sgabeblack@google.com        int64_t seek(uint64_t pos) override;
21712860Sgabeblack@google.com
21812860Sgabeblack@google.com      protected:
21912860Sgabeblack@google.com        size_t pos;
22012860Sgabeblack@google.com    };
22112860Sgabeblack@google.com
22212860Sgabeblack@google.com    class File : public FileBase
22312860Sgabeblack@google.com    {
22412860Sgabeblack@google.com      public:
22512860Sgabeblack@google.com        File(ArmSemihosting &_parent, const char *name, const char *mode);
22612860Sgabeblack@google.com        ~File();
22712860Sgabeblack@google.com
22812860Sgabeblack@google.com        void serialize(CheckpointOut &cp) const override;
22912860Sgabeblack@google.com        void unserialize(CheckpointIn &cp) override;
23012860Sgabeblack@google.com
23112860Sgabeblack@google.com        int64_t open() override { return openImpl(false); }
23212861Sgabeblack@google.com        int64_t close() override;
23312861Sgabeblack@google.com        bool isTTY() const override;
23412860Sgabeblack@google.com        int64_t read(uint8_t *buffer, uint64_t size) override;
23512860Sgabeblack@google.com        int64_t write(const uint8_t *buffer, uint64_t size) override;
23612860Sgabeblack@google.com        int64_t seek(uint64_t pos) override;
23712860Sgabeblack@google.com        int64_t flen() override;
23812860Sgabeblack@google.com
23912860Sgabeblack@google.com      protected:
24012860Sgabeblack@google.com        int64_t openImpl(bool unserialize);
24112860Sgabeblack@google.com        bool needClose() const { return !isTTY(); }
24212860Sgabeblack@google.com
24312860Sgabeblack@google.com        FILE *file;
24412860Sgabeblack@google.com    };
24512860Sgabeblack@google.com
24612861Sgabeblack@google.com    std::vector<std::unique_ptr<FileBase>> files;
24712860Sgabeblack@google.com
24812860Sgabeblack@google.com  protected: // Helper functions
24912837Sgabeblack@google.com    unsigned calcTickShift() const {
250        int msb = findMsbSet(SimClock::Frequency);
251        return msb > 31 ? msb - 31 : 0;
252    }
253    uint64_t semiTick(Tick tick) const {
254        return tick >> tickShift;
255    }
256    void semiExit(uint64_t code, uint64_t subcode);
257    PortProxy &physProxy(ThreadContext *tc);
258    std::string readString(ThreadContext *tc, Addr ptr, size_t len);
259
260    std::unique_ptr<PortProxy> physProxyS;
261
262  private:
263    typedef std::pair<uint64_t, SemiErrno> RetErrno;
264    static constexpr RetErrno retError(SemiErrno e) {
265        return RetErrno((uint64_t)-1, e);
266    }
267
268    static constexpr RetErrno retOK(uint64_t r) {
269        return RetErrno(r, 0);
270    }
271
272    /**
273     * Semihosting call information structure.
274     *
275     * This structure describes how a semi-hosting call is
276     * implemented. It contains debug information (e.g., the name of
277     * the call), a pointer to the implementation, and information
278     * needed to read its parameters from guest memory.
279     */
280    struct SemiCall
281    {
282        /** Call name */
283        const char *name;
284
285        /**
286         * Pointer to  call implementation
287         *
288         * @param tc ThreadContext pointer for caller
289         * @param aarch64 True if in aarc64 mode, false otherwise.
290         * @parma argv Argument vector. argv[0] always corresponds to
291         *             the pointer to the argument list. Remaining
292         *             entries are read as consecutive words starting
293         *             at the address pointed to by argv[0].
294         * @return a (return value, errno) pair
295         */
296        RetErrno (ArmSemihosting::*call)(ThreadContext *tc, bool aarch64,
297                                         std::vector<uint64_t> &argv);
298
299        /** Number of aarch32 arguments to read from guest memory. -1
300         * if unimplemented.*/
301        int argc32;
302        /** Number of aarch32 arguments to read from guest memory. -1
303         * if unimplemented.*/
304        int argc64;
305
306        /** Is call implemented in aarch32? */
307        bool implemented32() const { return call && argc32 >= 0; }
308        /** Is call implemented in aarch64? */
309        bool implemented64() const { return call && argc64 >= 0; }
310    };
311
312#define SEMI_CALL(N)                                                    \
313    RetErrno call ## N (ThreadContext *tc,                              \
314                        bool aarch64, std::vector<uint64_t> &argv)
315
316    SEMI_CALL(Open);
317    SEMI_CALL(Close);
318    SEMI_CALL(WriteC);
319    SEMI_CALL(Write0);
320    SEMI_CALL(Write);
321    SEMI_CALL(Read);
322    SEMI_CALL(ReadC);
323    SEMI_CALL(IsError);
324    SEMI_CALL(IsTTY);
325    SEMI_CALL(Seek);
326    SEMI_CALL(FLen);
327    SEMI_CALL(TmpNam);
328    SEMI_CALL(Remove);
329    SEMI_CALL(Rename);
330    SEMI_CALL(Clock);
331    SEMI_CALL(Time);
332    SEMI_CALL(System);
333    SEMI_CALL(Errno);
334    SEMI_CALL(GetCmdLine);
335    SEMI_CALL(HeapInfo);
336    SEMI_CALL(Exit);
337    SEMI_CALL(ExitExtended);
338
339    SEMI_CALL(Elapsed);
340    SEMI_CALL(TickFreq);
341
342#undef SEMI_CALL
343
344    static const SemiCall *getCall(uint32_t op, bool aarch64);
345
346    static const std::map<uint32_t, SemiCall> calls;
347    static const std::vector<const char *> fmodes;
348    static const std::map<uint64_t, const char *> exitCodes;
349    static const std::vector<uint8_t> features;
350};
351
352#endif // __ARCH_ARM_SEMIHOSTING_HH__
353