From 175355f71e18e8e8ed401bd267646aa850dc900e Mon Sep 17 00:00:00 2001 From: Gabe Black Date: Tue, 20 Oct 2020 17:36:57 -0700 Subject: [PATCH] sparc: Implement an SE workload for Linux and Solaris. I don't have a binary to test Solaris SE mode, but this *should* still work. Change-Id: Iaacc2ddd5193d7341bc65b9fdd5657c26d231cf1 Reviewed-on: https://gem5-review.googlesource.com/c/public/gem5/+/33995 Reviewed-by: Gabe Black Maintainer: Gabe Black Tested-by: kokoro --- src/arch/sparc/SConscript | 6 +- src/arch/sparc/SparcSeWorkload.py | 54 +++++++ src/arch/sparc/faults.cc | 5 +- .../linux/{process.cc => se_workload.cc} | 125 ++++++++-------- .../linux/{process.hh => se_workload.hh} | 64 +++----- src/arch/sparc/linux/syscalls.cc | 13 +- src/arch/sparc/process.cc | 114 --------------- src/arch/sparc/process.hh | 101 +------------ src/arch/sparc/se_workload.cc | 137 ++++++++++++++++++ src/arch/sparc/se_workload.hh | 125 ++++++++++++++++ .../solaris/{process.cc => se_workload.cc} | 61 ++++---- .../solaris/{process.hh => se_workload.hh} | 42 +++--- 12 files changed, 480 insertions(+), 367 deletions(-) create mode 100644 src/arch/sparc/SparcSeWorkload.py rename src/arch/sparc/linux/{process.cc => se_workload.cc} (50%) rename src/arch/sparc/linux/{process.hh => se_workload.hh} (54%) create mode 100644 src/arch/sparc/se_workload.cc create mode 100644 src/arch/sparc/se_workload.hh rename src/arch/sparc/solaris/{process.cc => se_workload.cc} (89%) rename src/arch/sparc/solaris/{process.hh => se_workload.hh} (69%) diff --git a/src/arch/sparc/SConscript b/src/arch/sparc/SConscript index 4c855ba4d..7ba6d10b0 100644 --- a/src/arch/sparc/SConscript +++ b/src/arch/sparc/SConscript @@ -36,14 +36,15 @@ if env['TARGET_ISA'] == 'sparc': Source('interrupts.cc') Source('isa.cc') Source('linux/linux.cc') - Source('linux/process.cc') + Source('linux/se_workload.cc') Source('linux/syscalls.cc') Source('mmu.cc') Source('nativetrace.cc') Source('pagetable.cc') Source('process.cc') Source('remote_gdb.cc') - Source('solaris/process.cc') + Source('se_workload.cc') + Source('solaris/se_workload.cc') Source('solaris/solaris.cc') Source('tlb.cc') Source('ua2005.cc') @@ -54,6 +55,7 @@ if env['TARGET_ISA'] == 'sparc': SimObject('SparcISA.py') SimObject('SparcMMU.py') SimObject('SparcNativeTrace.py') + SimObject('SparcSeWorkload.py') SimObject('SparcTLB.py') DebugFlag('Sparc', "Generic SPARC ISA stuff") diff --git a/src/arch/sparc/SparcSeWorkload.py b/src/arch/sparc/SparcSeWorkload.py new file mode 100644 index 000000000..03d4b7301 --- /dev/null +++ b/src/arch/sparc/SparcSeWorkload.py @@ -0,0 +1,54 @@ +# Copyright 2020 Google Inc. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer; +# redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution; +# neither the name of the copyright holders nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +from m5.params import * + +from m5.objects.Workload import SEWorkload + +class SparcSEWorkload(SEWorkload): + type = 'SparcSEWorkload' + cxx_header = "arch/sparc/se_workload.hh" + cxx_class = 'SparcISA::SEWorkload' + abstract = True + +class SparcEmuLinux(SparcSEWorkload): + type = 'SparcEmuLinux' + cxx_header = "arch/sparc/linux/se_workload.hh" + cxx_class = 'SparcISA::EmuLinux' + + @classmethod + def _is_compatible_with(cls, obj): + return obj.get_arch() in ('sparc64', 'sparc32') and \ + obj.get_op_sys() in ('linux', 'unknown') + +class SparcEmuSolaris(SparcSEWorkload): + type = 'SparcEmuSolaris' + cxx_header = "arch/sparc/solaris/se_workload.hh" + cxx_class = 'SparcISA::EmuSolaris' + + @classmethod + def _is_compatible_with(cls, obj): + return obj.get_arch() in ('sparc64', 'sparc32') and \ + obj.get_op_sys() == 'solaris' diff --git a/src/arch/sparc/faults.cc b/src/arch/sparc/faults.cc index 34a0d52b2..33ba921db 100644 --- a/src/arch/sparc/faults.cc +++ b/src/arch/sparc/faults.cc @@ -30,8 +30,8 @@ #include -#include "arch/sparc/isa_traits.hh" #include "arch/sparc/process.hh" +#include "arch/sparc/se_workload.hh" #include "arch/sparc/tlb.hh" #include "arch/sparc/types.hh" #include "base/bitfield.hh" @@ -815,7 +815,8 @@ TrapInstruction::invoke(ThreadContext *tc, const StaticInstPtr &inst) SparcProcess *sp = dynamic_cast(p); assert(sp); - sp->handleTrap(_n, tc); + auto *workload = dynamic_cast(tc->getSystemPtr()->workload); + workload->handleTrap(tc, _n); // We need to explicitly advance the pc, since that's not done for us // on a faulting instruction diff --git a/src/arch/sparc/linux/process.cc b/src/arch/sparc/linux/se_workload.cc similarity index 50% rename from src/arch/sparc/linux/process.cc rename to src/arch/sparc/linux/se_workload.cc index 37205c765..7b652ff01 100644 --- a/src/arch/sparc/linux/process.cc +++ b/src/arch/sparc/linux/se_workload.cc @@ -1,6 +1,5 @@ /* - * Copyright (c) 2003-2005 The Regents of The University of Michigan - * All rights reserved. + * Copyright 2020 Google Inc. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are @@ -26,32 +25,27 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#include "arch/sparc/linux/process.hh" +#include "arch/sparc/linux/se_workload.hh" -#include "arch/sparc/isa_traits.hh" -#include "arch/sparc/registers.hh" +#include + +#include "arch/sparc/process.hh" #include "base/loader/object_file.hh" #include "base/trace.hh" #include "cpu/thread_context.hh" -#include "kern/linux/linux.hh" -#include "sim/process.hh" #include "sim/syscall_desc.hh" -#include "sim/syscall_emul.hh" - -using namespace std; -using namespace SparcISA; namespace { -class SparcLinuxObjectFileLoader : public Process::Loader +class LinuxLoader : public Process::Loader { public: Process * - load(const ProcessParams ¶ms, ::Loader::ObjectFile *obj_file) override + load(const ProcessParams ¶ms, ::Loader::ObjectFile *obj) override { - auto arch = obj_file->getArch(); - auto opsys = obj_file->getOpSys(); + auto arch = obj->getArch(); + auto opsys = obj->getOpSys(); if (arch != ::Loader::SPARC64 && arch != ::Loader::SPARC32) return nullptr; @@ -65,79 +59,86 @@ class SparcLinuxObjectFileLoader : public Process::Loader return nullptr; if (arch == ::Loader::SPARC64) - return new Sparc64LinuxProcess(params, obj_file); + return new Sparc64Process(params, obj); else - return new Sparc32LinuxProcess(params, obj_file); + return new Sparc32Process(params, obj); } }; -SparcLinuxObjectFileLoader loader; +LinuxLoader loader; } // anonymous namespace -Sparc32LinuxProcess::Sparc32LinuxProcess(const ProcessParams ¶ms, - ::Loader::ObjectFile *objFile) - : Sparc32Process(params, objFile) +namespace SparcISA +{ + +EmuLinux::EmuLinux(const Params &p) : SEWorkload(p), _params(p) {} void -Sparc32LinuxProcess::syscall(ThreadContext *tc) +EmuLinux::handleTrap(ThreadContext *tc, int trapNum) { - Sparc32Process::syscall(tc); - syscall32Descs.get(tc->readIntReg(1))->doSyscall(tc); + if (is64(tc)) { + switch (trapNum) { + // case 0x10: // Linux 32 bit syscall trap + case 0x6d: // Linux 64 bit syscall trap + syscall64(tc); + return; + case 0x6e: // Linux 64 bit getcontext trap + warn("The getcontext trap is not implemented on SPARC"); + return; + case 0x6f: // Linux 64 bit setcontext trap + panic("The setcontext trap is not implemented on SPARC"); + default: + break; + } + } else { + switch (trapNum) { + case 0x10: //Linux 32 bit syscall trap + syscall32(tc); + return; + default: + break; + } + } + SEWorkload::handleTrap(tc, trapNum); } void -Sparc32LinuxProcess::handleTrap(int trapNum, ThreadContext *tc) +EmuLinux::syscall32(ThreadContext *tc) { - switch (trapNum) { - case 0x10: //Linux 32 bit syscall trap - tc->getSystemPtr()->workload->syscall(tc); - break; - default: - SparcProcess::handleTrap(trapNum, tc); - } -} + Process *process = tc->getProcessPtr(); + // Call the syscall function in the base Process class to update stats. + // This will move into the base SEWorkload function at some point. + process->Process::syscall(tc); -Sparc64LinuxProcess::Sparc64LinuxProcess(const ProcessParams ¶ms, - ::Loader::ObjectFile *objFile) - : Sparc64Process(params, objFile) -{} + syscall32Descs.get(tc->readIntReg(1))->doSyscall(tc); +} void -Sparc64LinuxProcess::syscall(ThreadContext *tc) +EmuLinux::syscall64(ThreadContext *tc) { - Sparc64Process::syscall(tc); + Process *process = tc->getProcessPtr(); + // Call the syscall function in the base Process class to update stats. + // This will move into the base SEWorkload function at some point. + process->Process::syscall(tc); + syscallDescs.get(tc->readIntReg(1))->doSyscall(tc); } void -Sparc64LinuxProcess::getContext(ThreadContext *tc) +EmuLinux::syscall(ThreadContext *tc) { - warn("The getcontext trap is not implemented on SPARC"); + if (is64(tc)) + syscall64(tc); + else + syscall32(tc); } -void -Sparc64LinuxProcess::setContext(ThreadContext *tc) -{ - panic("The setcontext trap is not implemented on SPARC"); -} +} // namespace SparcISA -void -Sparc64LinuxProcess::handleTrap(int trapNum, ThreadContext *tc) +SparcISA::EmuLinux * +SparcEmuLinuxParams::create() const { - switch (trapNum) { - // case 0x10: // Linux 32 bit syscall trap - case 0x6d: // Linux 64 bit syscall trap - tc->getSystemPtr()->workload->syscall(tc); - break; - case 0x6e: // Linux 64 bit getcontext trap - getContext(tc); - break; - case 0x6f: // Linux 64 bit setcontext trap - setContext(tc); - break; - default: - SparcProcess::handleTrap(trapNum, tc); - } + return new SparcISA::EmuLinux(*this); } diff --git a/src/arch/sparc/linux/process.hh b/src/arch/sparc/linux/se_workload.hh similarity index 54% rename from src/arch/sparc/linux/process.hh rename to src/arch/sparc/linux/se_workload.hh index c1ade86d0..a5022d6f9 100644 --- a/src/arch/sparc/linux/process.hh +++ b/src/arch/sparc/linux/se_workload.hh @@ -1,6 +1,5 @@ /* - * Copyright (c) 2003-2004 The Regents of The University of Michigan - * All rights reserved. + * Copyright 2020 Google Inc. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are @@ -26,60 +25,45 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef __SPARC_LINUX_PROCESS_HH__ -#define __SPARC_LINUX_PROCESS_HH__ +#ifndef __ARCH_SPARC_LINUX_SE_WORKLOAD_HH__ +#define __ARCH_SPARC_LINUX_SE_WORKLOAD_HH__ #include "arch/sparc/linux/linux.hh" -#include "arch/sparc/process.hh" -#include "sim/process.hh" +#include "arch/sparc/se_workload.hh" +#include "params/SparcEmuLinux.hh" #include "sim/syscall_desc.hh" -namespace SparcISA { +namespace SparcISA +{ -// This contains all of the common elements of a SPARC Linux process which -// are not shared by other operating systems. The rest come from the common -// SPARC process class. -class SparcLinuxProcess +class EmuLinux : public SEWorkload { public: - /// 64 bit syscall descriptors, indexed by call number. - static SyscallDescTable syscallDescs; + using Params = SparcEmuLinuxParams; - /// 32 bit compatibility syscall descriptors, indexed by call number. - static SyscallDescTable syscall32Descs; -}; + protected: + const Params &_params; -/// A process with emulated SPARC/Linux syscalls. -class Sparc32LinuxProcess : public SparcLinuxProcess, public Sparc32Process -{ - public: - /// Constructor. - Sparc32LinuxProcess(const ProcessParams ¶ms, - ::Loader::ObjectFile *objFile); + /// 64 bit syscall descriptors, indexed by call number. + static SyscallDescTable syscallDescs; - void syscall(ThreadContext *tc) override; + /// 32 bit compatibility syscall descriptors, indexed by call number. + static SyscallDescTable syscall32Descs; - void handleTrap(int trapNum, ThreadContext *tc) override; -}; + void syscall64(ThreadContext *tc); + void syscall32(ThreadContext *tc); -/// A process with emulated 32 bit SPARC/Linux syscalls. -class Sparc64LinuxProcess : public SparcLinuxProcess, public Sparc64Process -{ public: - /// Constructor. - Sparc64LinuxProcess(const ProcessParams ¶ms, - ::Loader::ObjectFile *objFile); + const Params ¶ms() const { return _params; } - void syscall(ThreadContext *tc) override; + EmuLinux(const Params &p); - void getContext(ThreadContext *tc); - void setContext(ThreadContext *tc); + ::Loader::Arch getArch() const override { return ::Loader::SPARC64; } - void handleTrap(int trapNum, ThreadContext *tc) override; + void handleTrap(ThreadContext *tc, int trapNum) override; + void syscall(ThreadContext *tc) override; }; -SyscallReturn getresuidFunc(SyscallDesc *desc, ThreadContext *tc, - Addr ruid, Addr euid, Addr suid); - } // namespace SparcISA -#endif // __SPARC_LINUX_PROCESS_HH__ + +#endif // __ARCH_SPARC_LINUX_SE_WORKLOAD_HH__ diff --git a/src/arch/sparc/linux/syscalls.cc b/src/arch/sparc/linux/syscalls.cc index 304f2cfdb..a00f60e59 100644 --- a/src/arch/sparc/linux/syscalls.cc +++ b/src/arch/sparc/linux/syscalls.cc @@ -26,14 +26,15 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#include "arch/sparc/linux/process.hh" +#include "arch/sparc/linux/se_workload.hh" #include "sim/syscall_desc.hh" #include "sim/syscall_emul.hh" class Process; class ThreadContext; -namespace SparcISA { +namespace SparcISA +{ /// Target uname() handler. static SyscallReturn @@ -51,7 +52,7 @@ unameFunc(SyscallDesc *desc, ThreadContext *tc, VPtr name) } -SyscallReturn +static SyscallReturn getresuidFunc(SyscallDesc *desc, ThreadContext *tc, Addr ruid, Addr euid, Addr suid) { @@ -78,8 +79,7 @@ getresuidFunc(SyscallDesc *desc, ThreadContext *tc, return 0; } -SyscallDescTable - SparcLinuxProcess::syscall32Descs = { +SyscallDescTable EmuLinux::syscall32Descs = { { 0, "restart_syscall" }, { 1, "exit", exitFunc }, // 32 bit { 2, "fork" }, @@ -382,8 +382,7 @@ SyscallDescTable { 299, "unshare" } }; -SyscallDescTable - SparcLinuxProcess::syscallDescs = { +SyscallDescTable EmuLinux::syscallDescs = { { 0, "restart_syscall" }, { 1, "exit", exitFunc }, { 2, "fork" }, diff --git a/src/arch/sparc/process.cc b/src/arch/sparc/process.cc index 8f3509f8a..b292c86a8 100644 --- a/src/arch/sparc/process.cc +++ b/src/arch/sparc/process.cc @@ -48,10 +48,6 @@ using namespace std; using namespace SparcISA; -const std::vector SparcProcess::SyscallABI::ArgumentRegs = { - INTREG_O0, INTREG_O1, INTREG_O2, INTREG_O3, INTREG_O4, INTREG_O5 -}; - SparcProcess::SparcProcess(const ProcessParams ¶ms, ::Loader::ObjectFile *objFile, Addr _StackBias) : Process(params, @@ -65,47 +61,6 @@ SparcProcess::SparcProcess(const ProcessParams ¶ms, spillStart = 0; } -void -SparcProcess::handleTrap(int trapNum, ThreadContext *tc) -{ - PCState pc = tc->pcState(); - switch (trapNum) { - case 0x01: // Software breakpoint - warn("Software breakpoint encountered at pc %#x.\n", pc.pc()); - break; - case 0x02: // Division by zero - warn("Software signaled a division by zero at pc %#x.\n", pc.pc()); - break; - case 0x03: // Flush window trap - flushWindows(tc); - break; - case 0x04: // Clean windows - warn("Ignoring process request for clean register " - "windows at pc %#x.\n", pc.pc()); - break; - case 0x05: // Range check - warn("Software signaled a range check at pc %#x.\n", pc.pc()); - break; - case 0x06: // Fix alignment - warn("Ignoring process request for os assisted unaligned accesses " - "at pc %#x.\n", pc.pc()); - break; - case 0x07: // Integer overflow - warn("Software signaled an integer overflow at pc %#x.\n", pc.pc()); - break; - case 0x32: // Get integer condition codes - warn("Ignoring process request to get the integer condition codes " - "at pc %#x.\n", pc.pc()); - break; - case 0x33: // Set integer condition codes - warn("Ignoring process request to set the integer condition codes " - "at pc %#x.\n", pc.pc()); - break; - default: - panic("Unimplemented trap to operating system: trap number %#x.\n", trapNum); - } -} - void SparcProcess::initState() { @@ -433,72 +388,3 @@ Sparc32Process::argsInit(int intSize, int pageSize) initVirtMem->writeBlob(spillStart, spillHandler32, sizeof(MachInst) * numSpillInsts); } - -void Sparc32Process::flushWindows(ThreadContext *tc) -{ - RegVal Cansave = tc->readIntReg(INTREG_CANSAVE); - RegVal Canrestore = tc->readIntReg(INTREG_CANRESTORE); - RegVal Otherwin = tc->readIntReg(INTREG_OTHERWIN); - RegVal CWP = tc->readMiscReg(MISCREG_CWP); - RegVal origCWP = CWP; - CWP = (CWP + Cansave + 2) % NWindows; - while (NWindows - 2 - Cansave != 0) { - if (Otherwin) { - panic("Otherwin non-zero.\n"); - } else { - tc->setMiscReg(MISCREG_CWP, CWP); - // Do the stores - RegVal sp = tc->readIntReg(StackPointerReg); - for (int index = 16; index < 32; index++) { - uint32_t regVal = tc->readIntReg(index); - regVal = htobe(regVal); - if (!tc->getVirtProxy().tryWriteBlob( - sp + (index - 16) * 4, (uint8_t *)®Val, 4)) { - warn("Failed to save register to the stack when " - "flushing windows.\n"); - } - } - Canrestore--; - Cansave++; - CWP = (CWP + 1) % NWindows; - } - } - tc->setIntReg(INTREG_CANSAVE, Cansave); - tc->setIntReg(INTREG_CANRESTORE, Canrestore); - tc->setMiscReg(MISCREG_CWP, origCWP); -} - -void -Sparc64Process::flushWindows(ThreadContext *tc) -{ - RegVal Cansave = tc->readIntReg(INTREG_CANSAVE); - RegVal Canrestore = tc->readIntReg(INTREG_CANRESTORE); - RegVal Otherwin = tc->readIntReg(INTREG_OTHERWIN); - RegVal CWP = tc->readMiscReg(MISCREG_CWP); - RegVal origCWP = CWP; - CWP = (CWP + Cansave + 2) % NWindows; - while (NWindows - 2 - Cansave != 0) { - if (Otherwin) { - panic("Otherwin non-zero.\n"); - } else { - tc->setMiscReg(MISCREG_CWP, CWP); - // Do the stores - RegVal sp = tc->readIntReg(StackPointerReg); - for (int index = 16; index < 32; index++) { - RegVal regVal = tc->readIntReg(index); - regVal = htobe(regVal); - if (!tc->getVirtProxy().tryWriteBlob( - sp + 2047 + (index - 16) * 8, (uint8_t *)®Val, 8)) { - warn("Failed to save register to the stack when " - "flushing windows.\n"); - } - } - Canrestore--; - Cansave++; - CWP = (CWP + 1) % NWindows; - } - } - tc->setIntReg(INTREG_CANSAVE, Cansave); - tc->setIntReg(INTREG_CANRESTORE, Canrestore); - tc->setMiscReg(MISCREG_CWP, origCWP); -} diff --git a/src/arch/sparc/process.hh b/src/arch/sparc/process.hh index 593854a0d..4d3ebfe4b 100644 --- a/src/arch/sparc/process.hh +++ b/src/arch/sparc/process.hh @@ -34,12 +34,9 @@ #include #include "arch/sparc/isa_traits.hh" -#include "arch/sparc/miscregs.hh" #include "base/loader/object_file.hh" #include "mem/page_table.hh" -#include "sim/byteswap.hh" #include "sim/process.hh" -#include "sim/syscall_abi.hh" class SparcProcess : public Process { @@ -60,63 +57,18 @@ class SparcProcess : public Process public: - // Handles traps which request services from the operating system - virtual void handleTrap(int trapNum, ThreadContext *tc); - Addr readFillStart() { return fillStart; } Addr readSpillStart() { return spillStart; } - - virtual void flushWindows(ThreadContext *tc) = 0; - - struct SyscallABI - { - static const std::vector ArgumentRegs; - }; -}; - -namespace GuestABI -{ - -template -struct Result::value>> -{ - static void - store(ThreadContext *tc, const SyscallReturn &ret) - { - if (ret.suppressed() || ret.needsRetry()) - return; - - // check for error condition. SPARC syscall convention is to - // indicate success/failure in reg the carry bit of the ccr - // and put the return value itself in the standard return value reg. - SparcISA::PSTATE pstate = - tc->readMiscRegNoEffect(SparcISA::MISCREG_PSTATE); - SparcISA::CCR ccr = tc->readIntReg(SparcISA::INTREG_CCR); - RegVal val; - if (ret.successful()) { - ccr.xcc.c = ccr.icc.c = 0; - val = ret.returnValue(); - } else { - ccr.xcc.c = ccr.icc.c = 1; - val = ret.errnoValue(); - } - tc->setIntReg(SparcISA::INTREG_CCR, ccr); - if (pstate.am) - val = bits(val, 31, 0); - tc->setIntReg(SparcISA::ReturnValueReg, val); - if (ret.count() == 2) - tc->setIntReg(SparcISA::SyscallPseudoReturnReg, ret.value2()); - } }; -} // namespace GuestABI - class Sparc32Process : public SparcProcess { protected: + void initState() override; + + public: + Sparc32Process(const ProcessParams ¶ms, ::Loader::ObjectFile *objFile) : SparcProcess(params, objFile, 0) { @@ -142,44 +94,15 @@ class Sparc32Process : public SparcProcess mmap_end); } - void initState() override; - - public: - void argsInit(int intSize, int pageSize); - - void flushWindows(ThreadContext *tc) override; - - struct SyscallABI : public GenericSyscallABI32, - public SparcProcess::SyscallABI - {}; -}; - -namespace GuestABI -{ - -template -struct Argument::value>> -{ - using ABI = Sparc32Process::SyscallABI; - - static Arg - get(ThreadContext *tc, typename ABI::State &state) - { - panic_if(state + 1 >= ABI::ArgumentRegs.size(), - "Ran out of syscall argument registers."); - auto high = ABI::ArgumentRegs[state++]; - auto low = ABI::ArgumentRegs[state++]; - return (Arg)ABI::mergeRegs(tc, low, high); - } }; -} // namespace GuestABI - class Sparc64Process : public SparcProcess { protected: + void initState() override; + + public: Sparc64Process(const ProcessParams ¶ms, ::Loader::ObjectFile *objFile) : SparcProcess(params, objFile, 2047) @@ -205,17 +128,7 @@ class Sparc64Process : public SparcProcess mmap_end); } - void initState() override; - - public: - void argsInit(int intSize, int pageSize); - - void flushWindows(ThreadContext *tc) override; - - struct SyscallABI : public GenericSyscallABI64, - public SparcProcess::SyscallABI - {}; }; #endif // __SPARC_PROCESS_HH__ diff --git a/src/arch/sparc/se_workload.cc b/src/arch/sparc/se_workload.cc new file mode 100644 index 000000000..19a4e2b4f --- /dev/null +++ b/src/arch/sparc/se_workload.cc @@ -0,0 +1,137 @@ +/* + * Copyright 2020 Google Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "arch/sparc/se_workload.hh" + +#include "arch/sparc/process.hh" +#include "arch/sparc/registers.hh" +#include "arch/sparc/types.hh" +#include "base/logging.hh" +#include "cpu/thread_context.hh" + +namespace SparcISA +{ + +const std::vector SEWorkload::BaseSyscallABI::ArgumentRegs = { + INTREG_O0, INTREG_O1, INTREG_O2, INTREG_O3, INTREG_O4, INTREG_O5 +}; + +bool +SEWorkload::is64(ThreadContext *tc) +{ + return dynamic_cast(tc->getProcessPtr()); +} + +void +SEWorkload::handleTrap(ThreadContext *tc, int trapNum) +{ + PCState pc = tc->pcState(); + switch (trapNum) { + case 0x01: // Software breakpoint + warn("Software breakpoint encountered at pc %#x.", pc.pc()); + break; + case 0x02: // Division by zero + warn("Software signaled a division by zero at pc %#x.", pc.pc()); + break; + case 0x03: // Flush window trap + flushWindows(tc); + break; + case 0x04: // Clean windows + warn("Ignoring process request for clean register " + "windows at pc %#x.", pc.pc()); + break; + case 0x05: // Range check + warn("Software signaled a range check at pc %#x.", pc.pc()); + break; + case 0x06: // Fix alignment + warn("Ignoring process request for os assisted unaligned accesses " + "at pc %#x.", pc.pc()); + break; + case 0x07: // Integer overflow + warn("Software signaled an integer overflow at pc %#x.", pc.pc()); + break; + case 0x32: // Get integer condition codes + warn("Ignoring process request to get the integer condition codes " + "at pc %#x.", pc.pc()); + break; + case 0x33: // Set integer condition codes + warn("Ignoring process request to set the integer condition codes " + "at pc %#x.", pc.pc()); + break; + default: + panic("Unimplemented trap to operating system: trap number %#x.", + trapNum); + } +} + +void +SEWorkload::flushWindows(ThreadContext *tc) +{ + RegVal Cansave = tc->readIntReg(INTREG_CANSAVE); + RegVal Canrestore = tc->readIntReg(INTREG_CANRESTORE); + RegVal Otherwin = tc->readIntReg(INTREG_OTHERWIN); + RegVal CWP = tc->readMiscReg(MISCREG_CWP); + RegVal origCWP = CWP; + + const bool is_64 = is64(tc); + const size_t reg_bytes = is_64 ? 8 : 4; + uint8_t bytes[8]; + + CWP = (CWP + Cansave + 2) % NWindows; + while (NWindows - 2 - Cansave != 0) { + panic_if(Otherwin, "Otherwin non-zero."); + + tc->setMiscReg(MISCREG_CWP, CWP); + // Do the stores + RegVal sp = tc->readIntReg(StackPointerReg); + + Addr addr = is_64 ? sp + 2047 : sp; + for (int index = 16; index < 32; index++) { + if (is_64) { + uint64_t regVal = htobe(tc->readIntReg(index)); + memcpy(bytes, ®Val, reg_bytes); + } else { + uint32_t regVal = htobe(tc->readIntReg(index)); + memcpy(bytes, ®Val, reg_bytes); + } + if (!tc->getVirtProxy().tryWriteBlob(addr, bytes, reg_bytes)) { + warn("Failed to save register to the stack when " + "flushing windows."); + } + addr += reg_bytes; + } + Canrestore--; + Cansave++; + CWP = (CWP + 1) % NWindows; + } + + tc->setIntReg(INTREG_CANSAVE, Cansave); + tc->setIntReg(INTREG_CANRESTORE, Canrestore); + tc->setMiscReg(MISCREG_CWP, origCWP); +} + +} // namespace SparcISA diff --git a/src/arch/sparc/se_workload.hh b/src/arch/sparc/se_workload.hh new file mode 100644 index 000000000..e39261dc5 --- /dev/null +++ b/src/arch/sparc/se_workload.hh @@ -0,0 +1,125 @@ +/* + * Copyright 2020 Google Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __ARCH_SPARC_SE_WORKLOAD_HH__ +#define __ARCH_SPARC_SE_WORKLOAD_HH__ + +#include + +#include "arch/sparc/miscregs.hh" +#include "base/loader/object_file.hh" +#include "cpu/thread_context.hh" +#include "sim/se_workload.hh" +#include "sim/syscall_abi.hh" + +namespace SparcISA +{ + +class SEWorkload : public ::SEWorkload +{ + public: + using ::SEWorkload::SEWorkload; + + virtual void handleTrap(ThreadContext *tc, int trapNum); + virtual void flushWindows(ThreadContext *tc); + + bool is64(ThreadContext *tc); + + struct BaseSyscallABI + { + static const std::vector ArgumentRegs; + }; + + struct SyscallABI32 : public GenericSyscallABI32, + public BaseSyscallABI + {}; + + struct SyscallABI64 : public GenericSyscallABI64, + public BaseSyscallABI + {}; +}; + +} // namespace SparcISA + +namespace GuestABI +{ + +template +struct Result::value>> +{ + static void + store(ThreadContext *tc, const SyscallReturn &ret) + { + if (ret.suppressed() || ret.needsRetry()) + return; + + // check for error condition. SPARC syscall convention is to + // indicate success/failure in reg the carry bit of the ccr + // and put the return value itself in the standard return value reg. + SparcISA::PSTATE pstate = + tc->readMiscRegNoEffect(SparcISA::MISCREG_PSTATE); + SparcISA::CCR ccr = tc->readIntReg(SparcISA::INTREG_CCR); + RegVal val; + if (ret.successful()) { + ccr.xcc.c = ccr.icc.c = 0; + val = ret.returnValue(); + } else { + ccr.xcc.c = ccr.icc.c = 1; + val = ret.errnoValue(); + } + tc->setIntReg(SparcISA::INTREG_CCR, ccr); + if (pstate.am) + val = bits(val, 31, 0); + tc->setIntReg(SparcISA::ReturnValueReg, val); + if (ret.count() == 2) + tc->setIntReg(SparcISA::SyscallPseudoReturnReg, ret.value2()); + } +}; + +template +struct Argument::value>> +{ + using ABI = SparcISA::SEWorkload::SyscallABI32; + + static Arg + get(ThreadContext *tc, typename ABI::State &state) + { + panic_if(state + 1 >= ABI::ArgumentRegs.size(), + "Ran out of syscall argument registers."); + auto high = ABI::ArgumentRegs[state++]; + auto low = ABI::ArgumentRegs[state++]; + return (Arg)ABI::mergeRegs(tc, low, high); + } +}; + +} // namespace GuestABI + +#endif // __ARCH_SPARC_SE_WORKLOAD_HH__ diff --git a/src/arch/sparc/solaris/process.cc b/src/arch/sparc/solaris/se_workload.cc similarity index 89% rename from src/arch/sparc/solaris/process.cc rename to src/arch/sparc/solaris/se_workload.cc index 442e984d8..9372f15b0 100644 --- a/src/arch/sparc/solaris/process.cc +++ b/src/arch/sparc/solaris/se_workload.cc @@ -1,6 +1,5 @@ /* - * Copyright (c) 2003-2005 The Regents of The University of Michigan - * All rights reserved. + * Copyright 2020 Google Inc. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are @@ -26,47 +25,60 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#include "arch/sparc/solaris/process.hh" +#include "arch/sparc/solaris/se_workload.hh" -#include "arch/sparc/isa_traits.hh" -#include "arch/sparc/registers.hh" +#include + +#include "arch/sparc/process.hh" #include "base/loader/object_file.hh" #include "base/trace.hh" #include "cpu/thread_context.hh" -#include "kern/solaris/solaris.hh" -#include "sim/process.hh" +#include "sim/proxy_ptr.hh" #include "sim/syscall_desc.hh" #include "sim/syscall_emul.hh" -using namespace std; -using namespace SparcISA; - namespace { -class SparcSolarisObjectFileLoader : public Process::Loader +class SolarisLoader : public Process::Loader { public: Process * - load(const ProcessParams ¶ms, ::Loader::ObjectFile *obj_file) override + load(const ProcessParams ¶ms, ::Loader::ObjectFile *obj) override { - auto arch = obj_file->getArch(); - auto opsys = obj_file->getOpSys(); + auto arch = obj->getArch(); + auto opsys = obj->getOpSys(); - if (arch != ::Loader::SPARC64 && arch != ::Loader::SPARC32) + if (arch != ::Loader::SPARC64) return nullptr; if (opsys != ::Loader::Solaris) return nullptr; - return new SparcSolarisProcess(params, obj_file); + return new Sparc64Process(params, obj); } }; -SparcSolarisObjectFileLoader loader; +SolarisLoader loader; } // anonymous namespace +namespace SparcISA +{ + +EmuSolaris::EmuSolaris(const Params &p) : SEWorkload(p), _params(p) +{} + +void +EmuSolaris::syscall(ThreadContext *tc) +{ + Process *process = tc->getProcessPtr(); + // Call the syscall function in the base Process class to update stats. + // This will move into the base SEWorkload function at some point. + process->Process::syscall(tc); + + syscallDescs.get(tc->readIntReg(1))->doSyscall(tc); +} /// Target uname() handler. static SyscallReturn @@ -84,8 +96,7 @@ unameFunc(SyscallDesc *desc, ThreadContext *tc, VPtr name) } -SyscallDescTable - SparcSolarisProcess::syscallDescs = { +SyscallDescTable EmuSolaris::syscallDescs = { { 0, "syscall" }, { 1, "exit", exitFunc }, { 2, "fork" }, @@ -344,14 +355,10 @@ SyscallDescTable { 255, "umount2" } }; -SparcSolarisProcess::SparcSolarisProcess(const ProcessParams ¶ms, - ::Loader::ObjectFile *objFile) : - Sparc64Process(params, objFile) -{} +} // namespace SparcISA -void -SparcSolarisProcess::syscall(ThreadContext *tc) +SparcISA::EmuSolaris * +SparcEmuSolarisParams::create() const { - Sparc64Process::syscall(tc); - syscallDescs.get(tc->readIntReg(1))->doSyscall(tc); + return new SparcISA::EmuSolaris(*this); } diff --git a/src/arch/sparc/solaris/process.hh b/src/arch/sparc/solaris/se_workload.hh similarity index 69% rename from src/arch/sparc/solaris/process.hh rename to src/arch/sparc/solaris/se_workload.hh index bd1860d85..3faf20f94 100644 --- a/src/arch/sparc/solaris/process.hh +++ b/src/arch/sparc/solaris/se_workload.hh @@ -1,6 +1,5 @@ /* - * Copyright (c) 2003-2004 The Regents of The University of Michigan - * All rights reserved. + * Copyright 2020 Google Inc. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are @@ -26,33 +25,38 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef __SPARC_SOLARIS_PROCESS_HH__ -#define __SPARC_SOLARIS_PROCESS_HH__ +#ifndef __ARCH_SPARC_SOLARIS_SE_WORKLOAD_HH__ +#define __ARCH_SPARC_SOLARIS_SE_WORKLOAD_HH__ +#include "arch/sparc/se_workload.hh" #include "arch/sparc/solaris/solaris.hh" -#include "arch/sparc/process.hh" -#include "sim/process.hh" +#include "params/SparcEmuSolaris.hh" #include "sim/syscall_desc.hh" -namespace SparcISA { +namespace SparcISA +{ -/// A process with emulated SPARC/Solaris syscalls. -class SparcSolarisProcess : public Sparc64Process +class EmuSolaris : public SEWorkload { public: - /// Constructor. - SparcSolarisProcess(const ProcessParams ¶ms, - ::Loader::ObjectFile *objFile); + using Params = SparcEmuSolarisParams; - /// The target system's hostname. - static const char *hostname; + protected: + const Params &_params; - void syscall(ThreadContext *tc) override; + /// Array of syscall descriptors, indexed by call number. + static SyscallDescTable syscallDescs; - /// Array of syscall descriptors, indexed by call number. - static SyscallDescTable syscallDescs; -}; + public: + const Params ¶ms() const { return _params; } + + EmuSolaris(const Params &p); + ::Loader::Arch getArch() const override { return ::Loader::SPARC64; } + + void syscall(ThreadContext *tc) override; +}; } // namespace SparcISA -#endif // __SPARC_SOLARIS_PROCESS_HH__ + +#endif // __ARCH_SPARC_SOLARIS_SE_WORKLOAD_HH__ -- 2.30.2