From 23c6e60409a580e53834f90c1de1438a8ac94e88 Mon Sep 17 00:00:00 2001 From: Andreas Sandberg Date: Wed, 21 Feb 2018 12:07:01 +0000 Subject: [PATCH] arch-arm: Add support for semihosting STDIO redirection The Arm Semihosting layer currently assumes that the guest application shares STDIO with gem5. This makes it hard to distinguish application output from gem5's output and makes it impossible to redirect STDIN when running in interactive mode. Add support for custom STDIO redirection when instantiating the Semihosting model. Change-Id: I3411a6b9bfb008ffc3087d8837f59be72bd1e8ae Signed-off-by: Andreas Sandberg Reviewed-by: Anouk Van Laer Reviewed-by: Jack Travaglini Reviewed-on: https://gem5-review.googlesource.com/10021 Reviewed-by: Giacomo Travaglini Maintainer: Giacomo Travaglini --- src/arch/arm/ArmSemihosting.py | 6 +++++ src/arch/arm/semihosting.cc | 42 ++++++++++++++++++++++++++++++---- src/arch/arm/semihosting.hh | 6 +++++ 3 files changed, 49 insertions(+), 5 deletions(-) diff --git a/src/arch/arm/ArmSemihosting.py b/src/arch/arm/ArmSemihosting.py index 1da4c4988..784649914 100644 --- a/src/arch/arm/ArmSemihosting.py +++ b/src/arch/arm/ArmSemihosting.py @@ -46,6 +46,12 @@ class ArmSemihosting(SimObject): cxx_header = "arch/arm/semihosting.hh" cmd_line = Param.String("", "Command line to report to guest"); + stdin = Param.String("stdin", + "Standard input (stdin for gem5's terminal)") + stdout = Param.String("stdout", + "Standard output (stdout for gem5's terminal)") + stderr = Param.String("stderr", + "Standard error (stderr for gem5's terminal)") mem_reserve = Param.MemorySize("32MB", "Amount of memory to reserve at the start of the address map. This " diff --git a/src/arch/arm/semihosting.cc b/src/arch/arm/semihosting.cc index 89e1b2e7d..46d964d63 100644 --- a/src/arch/arm/semihosting.cc +++ b/src/arch/arm/semihosting.cc @@ -121,6 +121,15 @@ const std::vector ArmSemihosting::features{ 0x3, // EXT_EXIT_EXTENDED, EXT_STDOUT_STDERR }; +const std::map ArmSemihosting::stdioMap{ + {"cin", ::stdin}, + {"stdin", ::stdin}, + {"cout", ::stdout}, + {"stdout", ::stdout}, + {"cerr", ::stderr}, + {"stderr", ::stderr}, +}; + ArmSemihosting::ArmSemihosting(const ArmSemihostingParams *p) : SimObject(p), cmdLine(p->cmd_line), @@ -128,7 +137,11 @@ ArmSemihosting::ArmSemihosting(const ArmSemihostingParams *p) stackSize(p->stack_size), timeBase([p]{ struct tm t = p->time; return mkutctime(&t); }()), tickShift(calcTickShift()), - semiErrno(0) + semiErrno(0), + stdin(getSTDIO("stdin", p->stdin, "r")), + stdout(getSTDIO("stdout", p->stdout, "w")), + stderr(p->stderr == p->stdout ? + stdout : getSTDIO("stderr", p->stderr, "w")) { // Create an empty place-holder file for position 0 as semi-hosting // calls typically expect non-zero file handles. @@ -681,6 +694,23 @@ ArmSemihosting::getCall(uint32_t op, bool aarch64) } } +FILE * +ArmSemihosting::getSTDIO(const char *stream_name, + const std::string &name, const char *mode) +{ + auto it = stdioMap.find(name); + if (it == stdioMap.end()) { + FILE *f = fopen(name.c_str(), mode); + if (!f) { + fatal("Failed to open %s (%s): %s\n", + stream_name, name, strerror(errno)); + } + return f; + } else { + return it->second; + } +} + std::unique_ptr ArmSemihosting::FileBase::create( ArmSemihosting &parent, const std::string &fname, const char *mode) @@ -819,11 +849,11 @@ ArmSemihosting::File::openImpl(bool in_cpt) if (_name == ":tt") { if (mode[0] == 'r') { - file = stdin; + file = parent.stdin; } else if (mode[0] == 'w') { - file = stdout; + file = parent.stdout; } else if (mode[0] == 'a') { - file = stderr; + file = parent.stderr; } else { warn("Unknown file mode for the ':tt' special file"); return -EINVAL; @@ -857,7 +887,9 @@ ArmSemihosting::File::close() bool ArmSemihosting::File::isTTY() const { - return file == stdout || file == stderr || file == stdin; + return file == parent.stdout || + file == parent.stderr || + file == parent.stdin; } int64_t diff --git a/src/arch/arm/semihosting.hh b/src/arch/arm/semihosting.hh index 14c5f9d2d..581646021 100644 --- a/src/arch/arm/semihosting.hh +++ b/src/arch/arm/semihosting.hh @@ -244,6 +244,9 @@ class ArmSemihosting : public SimObject }; std::vector> files; + FILE *stdin; + FILE *stdout; + FILE *stderr; protected: // Helper functions unsigned calcTickShift() const { @@ -342,11 +345,14 @@ class ArmSemihosting : public SimObject #undef SEMI_CALL static const SemiCall *getCall(uint32_t op, bool aarch64); + static FILE *getSTDIO(const char *stream_name, + const std::string &name, const char *mode); static const std::map calls; static const std::vector fmodes; static const std::map exitCodes; static const std::vector features; + static const std::map stdioMap; }; #endif // __ARCH_ARM_SEMIHOSTING_HH__ -- 2.30.2