Added functionality for the "get command line" semihosting command. PiperOrigin-RevId: 720273398 Change-Id: Id5c6d2876c1088bdd28a5d74042d9d328aafc721
diff --git a/riscv/riscv_arm_semihost.cc b/riscv/riscv_arm_semihost.cc index b3ba038..1d1523e 100644 --- a/riscv/riscv_arm_semihost.cc +++ b/riscv/riscv_arm_semihost.cc
@@ -21,6 +21,7 @@ #include <cerrno> #include <cstdint> #include <cstdio> +#include <cstring> #include <limits> #include <string> #include <utility> @@ -247,7 +248,7 @@ // Return the length of a file given by the file descriptor. absl::Status RiscVArmSemihost::SysFlen(uint64_t parameter, uint64_t *ret_val) { - // Load the targete file descriptor. + // Load the targeted file descriptor. d_memory_if_->Load(parameter, db1_, nullptr, nullptr); int target_fd = is_32_bit_ ? static_cast<int>(db1_->Get<uint32_t>(0)) : static_cast<int>(db1_->Get<uint64_t>(0)); @@ -273,8 +274,29 @@ // Currently unimplemented. Will implement if there is a demand. absl::Status RiscVArmSemihost::SysGetCmdline(uint64_t parameter, uint64_t *ret_val) { - return absl::UnimplementedError("SysGetCmdline not implemented"); - // TODO: Complete implementation. + d_memory_if_->Load(parameter, db2_, nullptr, nullptr); + uint64_t buffer_address = is_32_bit_ + ? static_cast<uint64_t>(db2_->Get<uint32_t>(0)) + : static_cast<uint64_t>(db2_->Get<uint64_t>(0)); + size_t buffer_len = is_32_bit_ ? static_cast<size_t>(db2_->Get<uint32_t>(1)) + : static_cast<size_t>(db2_->Get<uint64_t>(1)); + if (buffer_len <= cmd_line_.size()) { + *ret_val = -1ULL; + return absl::OkStatus(); + } + auto *db = db_factory_.Allocate<uint8_t>(cmd_line_.size() + 1); + std::memcpy(db->raw_ptr(), cmd_line_.c_str(), cmd_line_.size()); + db->Set<uint8_t>(cmd_line_.size(), 0); + d_memory_if_->Store(buffer_address, db); + db->DecRef(); + if (is_32_bit_) { + db2_->Set<uint32_t>(1, static_cast<uint32_t>(cmd_line_.size())); + } else { + db2_->Set<uint64_t>(1, cmd_line_.size()); + } + d_memory_if_->Store(parameter, db2_); + *ret_val = cmd_line_.size(); + return absl::OkStatus(); } // Returns 0 information indicating that the call doesn't provide this info.
diff --git a/riscv/riscv_arm_semihost.h b/riscv/riscv_arm_semihost.h index 19d89bd..39c3bc0 100644 --- a/riscv/riscv_arm_semihost.h +++ b/riscv/riscv_arm_semihost.h
@@ -17,10 +17,13 @@ #include <cstdint> #include <functional> +#include <string> +#include <vector> #include "absl/container/flat_hash_map.h" #include "absl/log/log.h" #include "absl/status/status.h" +#include "absl/strings/str_cat.h" #include "mpact/sim/generic/data_buffer.h" #include "mpact/sim/generic/instruction.h" #include "mpact/sim/util/memory/memory_interface.h" @@ -68,7 +71,17 @@ void OnEBreak(const Instruction *inst); // Return true if the instruction is a semihosting call. bool IsSemihostingCall(const Instruction *inst); + // Set the command line string. + void SetCmdLine(const std::vector<char *> &argv) { + cmd_line_.clear(); + std::string sep; + for (const auto &arg : argv) { + absl::StrAppend(&cmd_line_, sep, arg); + sep = " "; + } + } + // Setters. void set_exit_callback(std::function<void()> cb) { exit_callback_ = cb; } void set_exception_callback(std::function<void(uint64_t)> cb) { exception_callback_ = cb; @@ -144,13 +157,14 @@ generic::DataBuffer *db2_; // 2 word data buffer. generic::DataBuffer *db3_; // 3 word data buffer. generic::DataBuffer *db4_; // 4 word data buffer. - // Memory interfaces to use to access intstruction and data memory. + // Memory interfaces to use to access instruction and data memory. util::MemoryInterface *i_memory_if_; util::MemoryInterface *d_memory_if_; // Map from opcode to semihosting function. absl::flat_hash_map<uint64_t, SemihostOperation> semihost_operations_; // Map of target file descriptors to host file descriptors. absl::flat_hash_map<int, int> fd_map_; + std::string cmd_line_; }; } // namespace riscv
diff --git a/riscv/rv32g_sim.cc b/riscv/rv32g_sim.cc index c46e944..36e945e 100644 --- a/riscv/rv32g_sim.cc +++ b/riscv/rv32g_sim.cc
@@ -231,17 +231,15 @@ std::cerr << "Only one semihosting mechanism can be specified" << std::endl; } - if (arg_vec.size() > 2) { - std::cerr << "Only a single input file allowed" << std::endl; - return -1; - } + // Erase the simulator executable from arg_vec. + arg_vec.erase(arg_vec.begin()); bool quiet = absl::GetFlag(FLAGS_quiet); if (quiet) { absl::SetMinLogLevel(absl::LogSeverityAtLeast::kError); } - std::string full_file_name = arg_vec[1]; + std::string full_file_name = arg_vec[0]; std::string file_name = full_file_name.substr(full_file_name.find_last_of('/') + 1); std::string file_basename = file_name.substr(0, file_name.find_first_of('.')); @@ -442,6 +440,7 @@ // Add ARM semihosting. arm_semihost = new RiscVArmSemihost(RiscVArmSemihost::BitWidth::kWord32, memory, memory); + arm_semihost->SetCmdLine(arg_vec); riscv_top.state()->AddEbreakHandler( [arm_semihost](const Instruction *inst) -> bool { if (arm_semihost->IsSemihostingCall(inst)) { @@ -517,7 +516,7 @@ std::fstream proto_file(proto_file_name.c_str(), std::ios_base::out); std::string serialized; if (!proto_file.good() || !google::protobuf::TextFormat::PrintToString( - *component_proto.get(), &serialized)) { + *component_proto, &serialized)) { LOG(ERROR) << "Failed to write proto to file"; } else { proto_file << serialized;
diff --git a/riscv/rv32gv_sim.cc b/riscv/rv32gv_sim.cc index 94d1e65..c5b1cd3 100644 --- a/riscv/rv32gv_sim.cc +++ b/riscv/rv32gv_sim.cc
@@ -232,17 +232,15 @@ std::cerr << "Only one semihosting mechanism can be specified" << std::endl; } - if (arg_vec.size() > 2) { - std::cerr << "Only a single input file allowed" << std::endl; - return -1; - } + // Erase the simulator executable from arg_vec. + arg_vec.erase(arg_vec.begin()); bool quiet = absl::GetFlag(FLAGS_quiet); if (quiet) { absl::SetMinLogLevel(absl::LogSeverityAtLeast::kError); } - std::string full_file_name = arg_vec[1]; + std::string full_file_name = arg_vec[0]; std::string file_name = full_file_name.substr(full_file_name.find_last_of('/') + 1); std::string file_basename = file_name.substr(0, file_name.find_first_of('.')); @@ -423,6 +421,7 @@ // Add ARM semihosting. arm_semihost = new RiscVArmSemihost(RiscVArmSemihost::BitWidth::kWord32, memory, memory); + arm_semihost->SetCmdLine(arg_vec); riscv_top.state()->AddEbreakHandler( [arm_semihost](const Instruction *inst) -> bool { if (arm_semihost->IsSemihostingCall(inst)) { @@ -498,7 +497,7 @@ std::fstream proto_file(proto_file_name.c_str(), std::ios_base::out); std::string serialized; if (!proto_file.good() || !google::protobuf::TextFormat::PrintToString( - *component_proto.get(), &serialized)) { + *component_proto, &serialized)) { LOG(ERROR) << "Failed to write proto to file"; } else { proto_file << serialized;
diff --git a/riscv/rv64g_sim.cc b/riscv/rv64g_sim.cc index 71181b8..5f56635 100644 --- a/riscv/rv64g_sim.cc +++ b/riscv/rv64g_sim.cc
@@ -199,17 +199,14 @@ std::cerr << "Only one semihosting mechanism can be specified" << std::endl; } - if (arg_vec.size() > 2) { - std::cerr << "Only a single input file allowed" << std::endl; - return -1; - } + arg_vec.erase(arg_vec.begin()); bool quiet = absl::GetFlag(FLAGS_quiet); if (quiet) { absl::SetMinLogLevel(absl::LogSeverityAtLeast::kError); } - std::string full_file_name = arg_vec[1]; + std::string full_file_name = arg_vec[0]; std::string file_name = full_file_name.substr(full_file_name.find_last_of('/') + 1); std::string file_basename = file_name.substr(0, file_name.find_first_of('.')); @@ -366,6 +363,7 @@ // Add ARM semihosting. arm_semihost = new RiscVArmSemihost(RiscVArmSemihost::BitWidth::kWord64, memory, memory); + arm_semihost->SetCmdLine(arg_vec); riscv_top.state()->AddEbreakHandler( [arm_semihost](const Instruction *inst) { if (arm_semihost->IsSemihostingCall(inst)) {
diff --git a/riscv/rv64gv_sim.cc b/riscv/rv64gv_sim.cc index 113fa6f..4029017 100644 --- a/riscv/rv64gv_sim.cc +++ b/riscv/rv64gv_sim.cc
@@ -204,17 +204,14 @@ std::cerr << "Only one semihosting mechanism can be specified" << std::endl; } - if (arg_vec.size() > 2) { - std::cerr << "Only a single input file allowed" << std::endl; - return -1; - } + arg_vec.erase(arg_vec.begin()); bool quiet = absl::GetFlag(FLAGS_quiet); if (quiet) { absl::SetMinLogLevel(absl::LogSeverityAtLeast::kError); } - std::string full_file_name = arg_vec[1]; + std::string full_file_name = arg_vec[0]; std::string file_name = full_file_name.substr(full_file_name.find_last_of('/') + 1); std::string file_basename = file_name.substr(0, file_name.find_first_of('.')); @@ -378,6 +375,7 @@ // Add ARM semihosting. arm_semihost = new RiscVArmSemihost(RiscVArmSemihost::BitWidth::kWord64, memory, memory); + arm_semihost->SetCmdLine(arg_vec); riscv_top.state()->AddEbreakHandler( [arm_semihost](const Instruction *inst) { if (arm_semihost->IsSemihostingCall(inst)) { @@ -453,7 +451,7 @@ std::fstream proto_file(proto_file_name.c_str(), std::ios_base::out); std::string serialized; if (!proto_file.good() || !google::protobuf::TextFormat::PrintToString( - *component_proto.get(), &serialized)) { + *component_proto, &serialized)) { LOG(ERROR) << "Failed to write proto to file"; } else { proto_file << serialized;