2022.08.27

Syscall in Gem5 SE

  • build/X86/arch/x86/generated/exec-ns.cc.inc:

    Fault Int80::execute(...) {
      return std::make_shared<SESyscallFault>();
    }
    

    SESyscallFault is a class, defined as below.

    • src/sim/faults.hh:

      // A fault to trigger a system call in SE mode.
      class SESyscallFault : public FaultBase
      {
          const char *name() const override { return "syscall_fault"; }
          void invoke(ThreadContext *tc, const StaticInstPtr &inst=
                  nullStaticInstPtr) override;
      };
      

TODO: In IEW the SESyscallFault will be invoke.

  • src/sim/faults.cc:

    void SESyscallFault::invoke(ThreadContext *tc, const StaticInstPtr &inst)
    {
        // Move the PC forward since that doesn't happen automatically.
        std::unique_ptr<PCStateBase> pc(tc->pcState().clone());
        inst->advancePC(*pc);
        tc->pcState(*pc);
        tc->getSystemPtr()->workload->syscall(tc);
    }
    

    Assume we run a 32bit linux program.

    • src/arch/x86/linux/se_workload.cc:

      void EmuLinux::syscall(ThreadContext *tc) {
        ...
        syscallDescs32.get(rax)->doSyscall(tc);
      }
      
      • build/X86/sim/syscall_desc.cc:

        void SyscallDesc::doSyscall(ThreadContext *tc) {
          ...
          SyscallReturn retval = executor(this, tc);
          ...
        }
        

        The executor is a lambda function, see below.

        • src/sim/syscall_desc.hh:

          template <typename ...Args>
          static inline Executor buildExecutor(ABIExecutor<Args...> target) {
            return [target](SyscallDesc *desc, ThreadContext *tc) -> SyscallReturn {
              auto partial = [target,desc](ThreadContext *tc, Args... args) -> SyscallReturn {
                return target(desc, tc, args...);
              };
              return invokeSimcall<ABI, false, SyscallReturn, Args...>(tc, std::function<SyscallReturn(ThreadContext *, Args...)>(partial));
            };
          }
          

          partial will becomes target below.

          • build/X86/sim/guest_abi.hh:

            template <typename ABI, bool store_ret, typename Ret, typename ...Args>
            Ret invokeSimcall(ThreadContext *tc, std::function<Ret(ThreadContext *, Args...)> target) {
              ...
              return guest_abi::callFrom<ABI, Ret, store_ret, Args...>(tc, state, target);
            }
            
            • TODO: build/X86/sim/syscall_emul.hh:

              Here is actual write syscall, which is used by printf.

              template <class OS>
              SyscallReturn writeFunc(SyscallDesc *desc, ThreadContext *tc, int tgt_fd, VPtr<> buf_ptr, int nbytes) {
                ...
              }