process.cc revision 13883
12SN/A/* 210298Salexandru.dutu@amd.com * Copyright (c) 2014-2016 Advanced Micro Devices, Inc. 38852Sandreas.hansson@arm.com * Copyright (c) 2012 ARM Limited 48852Sandreas.hansson@arm.com * All rights reserved 58852Sandreas.hansson@arm.com * 68852Sandreas.hansson@arm.com * The license below extends only to copyright in the software and shall 78852Sandreas.hansson@arm.com * not be construed as granting a license to any other intellectual 88852Sandreas.hansson@arm.com * property including but not limited to intellectual property relating 98852Sandreas.hansson@arm.com * to a hardware implementation of the functionality of the software 108852Sandreas.hansson@arm.com * licensed hereunder. You may use the software subject to the license 118852Sandreas.hansson@arm.com * terms below provided that you ensure that this notice is replicated 128852Sandreas.hansson@arm.com * unmodified and in its entirety in all distributions of the software, 138852Sandreas.hansson@arm.com * modified or unmodified, in source code or in binary form. 148852Sandreas.hansson@arm.com * 151762SN/A * Copyright (c) 2001-2005 The Regents of The University of Michigan 162SN/A * All rights reserved. 172SN/A * 182SN/A * Redistribution and use in source and binary forms, with or without 192SN/A * modification, are permitted provided that the following conditions are 202SN/A * met: redistributions of source code must retain the above copyright 212SN/A * notice, this list of conditions and the following disclaimer; 222SN/A * redistributions in binary form must reproduce the above copyright 232SN/A * notice, this list of conditions and the following disclaimer in the 242SN/A * documentation and/or other materials provided with the distribution; 252SN/A * neither the name of the copyright holders nor the names of its 262SN/A * contributors may be used to endorse or promote products derived from 272SN/A * this software without specific prior written permission. 282SN/A * 292SN/A * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 302SN/A * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 312SN/A * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 322SN/A * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 332SN/A * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 342SN/A * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 352SN/A * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 362SN/A * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 372SN/A * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 382SN/A * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 392SN/A * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 402665Ssaidi@eecs.umich.edu * 412665Ssaidi@eecs.umich.edu * Authors: Nathan Binkert 422665Ssaidi@eecs.umich.edu * Steve Reinhardt 432665Ssaidi@eecs.umich.edu * Ali Saidi 442SN/A * Brandon Potter 452SN/A */ 4611793Sbrandon.potter@amd.com 4711793Sbrandon.potter@amd.com#include "sim/process.hh" 488229Snate@binkert.org 492SN/A#include <fcntl.h> 506712Snate@binkert.org#include <unistd.h> 5111800Sbrandon.potter@amd.com 5210930Sbrandon.potter@amd.com#include <array> 532SN/A#include <climits> 5411800Sbrandon.potter@amd.com#include <csignal> 552SN/A#include <map> 5611793Sbrandon.potter@amd.com#include <string> 5756SN/A#include <vector> 581158SN/A 59146SN/A#include "base/intmath.hh" 606658Snate@binkert.org#include "base/loader/object_file.hh" 612680Sktlim@umich.edu#include "base/loader/symtab.hh" 622378SN/A#include "base/statistics.hh" 638706Sandreas.hansson@arm.com#include "config/the_isa.hh" 645154Sgblack@eecs.umich.edu#include "cpu/thread_context.hh" 6511800Sbrandon.potter@amd.com#include "mem/page_table.hh" 6611794Sbrandon.potter@amd.com#include "mem/se_translating_port_proxy.hh" 672378SN/A#include "params/Process.hh" 682SN/A#include "sim/emul_driver.hh" 692715Sstever@eecs.umich.edu#include "sim/fd_array.hh" 702715Sstever@eecs.umich.edu#include "sim/fd_entry.hh" 712715Sstever@eecs.umich.edu#include "sim/redirect_path.hh" 722715Sstever@eecs.umich.edu#include "sim/syscall_desc.hh" 732715Sstever@eecs.umich.edu#include "sim/system.hh" 742715Sstever@eecs.umich.edu 752715Sstever@eecs.umich.edu#if THE_ISA == ALPHA_ISA 765335Shines@cs.fsu.edu#include "arch/alpha/linux/process.hh" 775335Shines@cs.fsu.edu 7810810Sbr@bsdpad.com#elif THE_ISA == SPARC_ISA 794157Sgblack@eecs.umich.edu#include "arch/sparc/linux/process.hh" 804166Sgblack@eecs.umich.edu#include "arch/sparc/solaris/process.hh" 816691Stjones1@inf.ed.ac.uk 826691Stjones1@inf.ed.ac.uk#elif THE_ISA == MIPS_ISA 8311723Sar4jc@virginia.edu#include "arch/mips/linux/process.hh" 8411723Sar4jc@virginia.edu 852715Sstever@eecs.umich.edu#elif THE_ISA == ARM_ISA 862715Sstever@eecs.umich.edu#include "arch/arm/freebsd/process.hh" 872715Sstever@eecs.umich.edu#include "arch/arm/linux/process.hh" 882715Sstever@eecs.umich.edu 892715Sstever@eecs.umich.edu#elif THE_ISA == X86_ISA 902SN/A#include "arch/x86/linux/process.hh" 912107SN/A 922SN/A#elif THE_ISA == POWER_ISA 932SN/A#include "arch/power/linux/process.hh" 942SN/A 952SN/A#elif THE_ISA == RISCV_ISA 965758Shsul@eecs.umich.edu#include "arch/riscv/linux/process.hh" 9710932Sbrandon.potter@amd.com 985771Shsul@eecs.umich.edu#else 995758Shsul@eecs.umich.edu#error "THE_ISA not set" 1005758Shsul@eecs.umich.edu#endif 1015758Shsul@eecs.umich.edu 1025758Shsul@eecs.umich.edu 1035758Shsul@eecs.umich.eduusing namespace std; 1048737Skoansin.tan@gmail.comusing namespace TheISA; 1058737Skoansin.tan@gmail.com 1065758Shsul@eecs.umich.edustatic std::string 10710930Sbrandon.potter@amd.comnormalize(std::string& directory) 10810930Sbrandon.potter@amd.com{ 10910930Sbrandon.potter@amd.com if (directory.back() != '/') 11010930Sbrandon.potter@amd.com directory += '/'; 11110930Sbrandon.potter@amd.com return directory; 11210930Sbrandon.potter@amd.com} 11310930Sbrandon.potter@amd.com 11410930Sbrandon.potter@amd.comProcess::Process(ProcessParams *params, EmulationPageTable *pTable, 11510930Sbrandon.potter@amd.com ObjectFile *obj_file) 11610930Sbrandon.potter@amd.com : SimObject(params), system(params->system), 11710930Sbrandon.potter@amd.com useArchPT(params->useArchPT), 11810930Sbrandon.potter@amd.com kvmInSE(params->kvmInSE), 11910930Sbrandon.potter@amd.com useForClone(false), 12010930Sbrandon.potter@amd.com pTable(pTable), 12110930Sbrandon.potter@amd.com initVirtMem(system->getSystemPort(), this, 12210930Sbrandon.potter@amd.com SETranslatingPortProxy::Always), 12310930Sbrandon.potter@amd.com objFile(obj_file), 12410930Sbrandon.potter@amd.com argv(params->cmd), envp(params->env), 12510930Sbrandon.potter@amd.com executable(params->executable), 12610930Sbrandon.potter@amd.com tgtCwd(normalize(params->cwd)), 12710930Sbrandon.potter@amd.com hostCwd(checkPathRedirect(tgtCwd)), 12811851Sbrandon.potter@amd.com _uid(params->uid), _euid(params->euid), 1297532Ssteve.reinhardt@amd.com _gid(params->gid), _egid(params->egid), 13010559Sandreas.hansson@arm.com _pid(params->pid), _ppid(params->ppid), 1318852Sandreas.hansson@arm.com _pgid(params->pgid), drivers(params->drivers), 13210559Sandreas.hansson@arm.com fds(make_shared<FDArray>(params->input, params->output, params->errout)), 13310299Salexandru.dutu@amd.com childClearTID(0) 13410554Salexandru.dutu@amd.com{ 13510299Salexandru.dutu@amd.com if (_pid >= System::maxPID) 13611813Sbaz21@cam.ac.uk fatal("_pid is too large: %d", _pid); 13711813Sbaz21@cam.ac.uk 13811813Sbaz21@cam.ac.uk auto ret_pair = system->PIDs.emplace(_pid); 1398852Sandreas.hansson@arm.com if (!ret_pair.second) 14010929Sbrandon.potter@amd.com fatal("_pid %d is already used", _pid); 14110930Sbrandon.potter@amd.com 14210930Sbrandon.potter@amd.com /** 14310930Sbrandon.potter@amd.com * Linux bundles together processes into this concept called a thread 14410930Sbrandon.potter@amd.com * group. The thread group is responsible for recording which processes 14510930Sbrandon.potter@amd.com * behave as threads within a process context. The thread group leader 14610930Sbrandon.potter@amd.com * is the process who's tgid is equal to its pid. Other processes which 14710930Sbrandon.potter@amd.com * belong to the thread group, but do not lead the thread group, are 14810930Sbrandon.potter@amd.com * treated as child threads. These threads are created by the clone system 14911801Sbrandon.potter@amd.com * call with options specified to create threads (differing from the 15011851Sbrandon.potter@amd.com * options used to implement a fork). By default, set up the tgid/pid 15111851Sbrandon.potter@amd.com * with a new, equivalent value. If CLONE_THREAD is specified, patch 15211851Sbrandon.potter@amd.com * the tgid value with the old process' value. 15311801Sbrandon.potter@amd.com */ 15411801Sbrandon.potter@amd.com _tgid = params->pid; 15511851Sbrandon.potter@amd.com 15611851Sbrandon.potter@amd.com exitGroup = new bool(); 1572SN/A sigchld = new bool(); 15810930Sbrandon.potter@amd.com 15910930Sbrandon.potter@amd.com if (!debugSymbolTable) { 1605154Sgblack@eecs.umich.edu debugSymbolTable = new SymbolTable(); 16110930Sbrandon.potter@amd.com if (!objFile->loadGlobalSymbols(debugSymbolTable) || 16210930Sbrandon.potter@amd.com !objFile->loadLocalSymbols(debugSymbolTable) || 16310932Sbrandon.potter@amd.com !objFile->loadWeakSymbols(debugSymbolTable)) { 16410930Sbrandon.potter@amd.com delete debugSymbolTable; 16510930Sbrandon.potter@amd.com debugSymbolTable = nullptr; 16610930Sbrandon.potter@amd.com } 16710930Sbrandon.potter@amd.com } 16810930Sbrandon.potter@amd.com} 1695154Sgblack@eecs.umich.edu 17010930Sbrandon.potter@amd.comvoid 17110930Sbrandon.potter@amd.comProcess::clone(ThreadContext *otc, ThreadContext *ntc, 17210932Sbrandon.potter@amd.com Process *np, RegVal flags) 17310930Sbrandon.potter@amd.com{ 17410930Sbrandon.potter@amd.com#ifndef CLONE_VM 1755154Sgblack@eecs.umich.edu#define CLONE_VM 0 17610930Sbrandon.potter@amd.com#endif 17710930Sbrandon.potter@amd.com#ifndef CLONE_FILES 17810930Sbrandon.potter@amd.com#define CLONE_FILES 0 1795154Sgblack@eecs.umich.edu#endif 18010932Sbrandon.potter@amd.com#ifndef CLONE_THREAD 18110930Sbrandon.potter@amd.com#define CLONE_THREAD 0 18210930Sbrandon.potter@amd.com#endif 18310930Sbrandon.potter@amd.com if (CLONE_VM & flags) { 18410930Sbrandon.potter@amd.com /** 18510930Sbrandon.potter@amd.com * Share the process memory address space between the new process 1865154Sgblack@eecs.umich.edu * and the old process. Changes in one will be visible in the other 18710930Sbrandon.potter@amd.com * due to the pointer use. 18810930Sbrandon.potter@amd.com */ 18910930Sbrandon.potter@amd.com delete np->pTable; 1902SN/A np->pTable = pTable; 19111386Ssteve.reinhardt@amd.com ntc->getMemProxy().setPageTable(np->pTable); 1921514SN/A 1932SN/A np->memState = memState; 19411851Sbrandon.potter@amd.com } else { 19511851Sbrandon.potter@amd.com /** 19611851Sbrandon.potter@amd.com * Duplicate the process memory address space. The state needs to be 19711851Sbrandon.potter@amd.com * copied over (rather than using pointers to share everything). 19811851Sbrandon.potter@amd.com */ 19911851Sbrandon.potter@amd.com typedef std::vector<pair<Addr,Addr>> MapVec; 20011851Sbrandon.potter@amd.com MapVec mappings; 20111851Sbrandon.potter@amd.com pTable->getMappings(&mappings); 20211851Sbrandon.potter@amd.com 20311851Sbrandon.potter@amd.com for (auto map : mappings) { 20411851Sbrandon.potter@amd.com Addr paddr, vaddr = map.first; 20511851Sbrandon.potter@amd.com bool alloc_page = !(np->pTable->translate(vaddr, paddr)); 20611851Sbrandon.potter@amd.com np->replicatePage(vaddr, paddr, otc, ntc, alloc_page); 2072SN/A } 2082SN/A 2092378SN/A *np->memState = *memState; 2102SN/A } 2112SN/A 2122SN/A if (CLONE_FILES & flags) { 21311522Sstephan.diestelhorst@arm.com /** 21411522Sstephan.diestelhorst@arm.com * The parent and child file descriptors are shared because the 215729SN/A * two FDArray pointers are pointing to the same FDArray. Opening 2162SN/A * and closing file descriptors will be visible to both processes. 2172SN/A */ 2188240Snate@binkert.org np->fds = fds; 2192SN/A } else { 2202SN/A /** 2212SN/A * Copy the file descriptors from the old process into the new 2222SN/A * child process. The file descriptors entry can be opened and 22310930Sbrandon.potter@amd.com * closed independently of the other process being considered. The 22410932Sbrandon.potter@amd.com * host file descriptors are also dup'd so that the flags for the 2252SN/A * host file descriptor is independent of the other process. 22610930Sbrandon.potter@amd.com */ 2272SN/A for (int tgt_fd = 0; tgt_fd < fds->getSize(); tgt_fd++) { 2282SN/A std::shared_ptr<FDArray> nfds = np->fds; 2295713Shsul@eecs.umich.edu std::shared_ptr<FDEntry> this_fde = (*fds)[tgt_fd]; 2305713Shsul@eecs.umich.edu if (!this_fde) { 2312SN/A nfds->setFDEntry(tgt_fd, nullptr); 23210929Sbrandon.potter@amd.com continue; 23310929Sbrandon.potter@amd.com } 23410929Sbrandon.potter@amd.com nfds->setFDEntry(tgt_fd, this_fde->clone()); 2355713Shsul@eecs.umich.edu 2365512SMichael.Adler@intel.com auto this_hbfd = std::dynamic_pointer_cast<HBFDEntry>(this_fde); 2375713Shsul@eecs.umich.edu if (!this_hbfd) 2382SN/A continue; 2392SN/A 2401395SN/A int this_sim_fd = this_hbfd->getSimFD(); 2417532Ssteve.reinhardt@amd.com if (this_sim_fd <= 2) 2421395SN/A continue; 2435713Shsul@eecs.umich.edu 2445713Shsul@eecs.umich.edu int np_sim_fd = dup(this_sim_fd); 2452378SN/A assert(np_sim_fd != -1); 2462680Sktlim@umich.edu 2475713Shsul@eecs.umich.edu auto nhbfd = std::dynamic_pointer_cast<HBFDEntry>((*nfds)[tgt_fd]); 2481395SN/A nhbfd->setSimFD(np_sim_fd); 2491634SN/A } 25010407Smitch.hayenga@arm.com } 25110298Salexandru.dutu@amd.com 25210298Salexandru.dutu@amd.com if (CLONE_THREAD & flags) { 2531395SN/A np->_tgid = _tgid; 2542SN/A delete np->exitGroup; 25510913Sandreas.sandberg@arm.com np->exitGroup = exitGroup; 25610913Sandreas.sandberg@arm.com } 25710905Sandreas.sandberg@arm.com 25810932Sbrandon.potter@amd.com np->argv.insert(np->argv.end(), argv.begin(), argv.end()); 25910913Sandreas.sandberg@arm.com np->envp.insert(np->envp.end(), envp.begin(), envp.end()); 26010905Sandreas.sandberg@arm.com} 26110905Sandreas.sandberg@arm.com 2622SN/Avoid 26310932Sbrandon.potter@amd.comProcess::regStats() 26410932Sbrandon.potter@amd.com{ 2652SN/A SimObject::regStats(); 26610930Sbrandon.potter@amd.com 26710932Sbrandon.potter@amd.com using namespace Stats; 26810930Sbrandon.potter@amd.com 26910930Sbrandon.potter@amd.com numSyscalls 2701970SN/A .name(name() + ".numSyscalls") 2711970SN/A .desc("Number of system calls") 2722SN/A ; 2732SN/A} 27410930Sbrandon.potter@amd.com 2751970SN/AThreadContext * 2762SN/AProcess::findFreeContext() 2771970SN/A{ 27810932Sbrandon.potter@amd.com for (auto &it : system->threadContexts) { 2791970SN/A if (ThreadContext::Halted == it->status()) 28010932Sbrandon.potter@amd.com return it; 28110930Sbrandon.potter@amd.com } 2821970SN/A return nullptr; 28310930Sbrandon.potter@amd.com} 2842SN/A 2852SN/Avoid 2862SN/AProcess::revokeThreadContext(int context_id) 28710932Sbrandon.potter@amd.com{ 2882SN/A std::vector<ContextID>::iterator it; 28910932Sbrandon.potter@amd.com for (it = contextIds.begin(); it != contextIds.end(); it++) { 29010930Sbrandon.potter@amd.com if (*it == context_id) { 2912SN/A contextIds.erase(it); 2922SN/A return; 29310930Sbrandon.potter@amd.com } 29410932Sbrandon.potter@amd.com } 2955282Srstrong@cs.ucsd.edu warn("Unable to find thread context to revoke"); 29610930Sbrandon.potter@amd.com} 29710930Sbrandon.potter@amd.com 29810929Sbrandon.potter@amd.comvoid 2995282Srstrong@cs.ucsd.eduProcess::initState() 30010929Sbrandon.potter@amd.com{ 30110932Sbrandon.potter@amd.com if (contextIds.empty()) 30210929Sbrandon.potter@amd.com fatal("Process %s is not associated with any HW contexts!\n", name()); 30310930Sbrandon.potter@amd.com 30410930Sbrandon.potter@amd.com // first thread context for this process... initialize & enable 30510929Sbrandon.potter@amd.com ThreadContext *tc = system->getThreadContext(contextIds[0]); 30610929Sbrandon.potter@amd.com 3075282Srstrong@cs.ucsd.edu // mark this context as active so it will start ticking. 3087487Ssteve.reinhardt@amd.com tc->activate(); 3098601Ssteve.reinhardt@amd.com 3108601Ssteve.reinhardt@amd.com pTable->initState(tc); 3118601Ssteve.reinhardt@amd.com} 31210318Sandreas.hansson@arm.com 3138601Ssteve.reinhardt@amd.comDrainState 31411294Sandreas.hansson@arm.comProcess::drain() 31511294Sandreas.hansson@arm.com{ 3168601Ssteve.reinhardt@amd.com fds->updateFileOffsets(); 3178601Ssteve.reinhardt@amd.com return DrainState::Drained; 3184434Ssaidi@eecs.umich.edu} 3198539Sgblack@eecs.umich.edu 3204434Ssaidi@eecs.umich.eduvoid 3218539Sgblack@eecs.umich.eduProcess::allocateMem(Addr vaddr, int64_t size, bool clobber) 3228539Sgblack@eecs.umich.edu{ 3234434Ssaidi@eecs.umich.edu int npages = divCeil(size, (int64_t)PageBytes); 32410318Sandreas.hansson@arm.com Addr paddr = system->allocPhysPages(npages); 3254434Ssaidi@eecs.umich.edu pTable->map(vaddr, paddr, size, 3264434Ssaidi@eecs.umich.edu clobber ? EmulationPageTable::Clobber : 3274434Ssaidi@eecs.umich.edu EmulationPageTable::MappingFlags(0)); 3288539Sgblack@eecs.umich.edu} 3298539Sgblack@eecs.umich.edu 3305154Sgblack@eecs.umich.eduvoid 3315154Sgblack@eecs.umich.eduProcess::replicatePage(Addr vaddr, Addr new_paddr, ThreadContext *old_tc, 3325154Sgblack@eecs.umich.edu ThreadContext *new_tc, bool allocate_page) 3338539Sgblack@eecs.umich.edu{ 3345154Sgblack@eecs.umich.edu if (allocate_page) 3358601Ssteve.reinhardt@amd.com new_paddr = system->allocPhysPages(1); 3365823Ssaidi@eecs.umich.edu 3375154Sgblack@eecs.umich.edu // Read from old physical page. 3384434Ssaidi@eecs.umich.edu uint8_t *buf_p = new uint8_t[PageBytes]; 3394434Ssaidi@eecs.umich.edu old_tc->getMemProxy().readBlob(vaddr, buf_p, PageBytes); 3404434Ssaidi@eecs.umich.edu 3414434Ssaidi@eecs.umich.edu // Create new mapping in process address space by clobbering existing 3424434Ssaidi@eecs.umich.edu // mapping (if any existed) and then write to the new physical page. 3435282Srstrong@cs.ucsd.edu bool clobber = true; 34410932Sbrandon.potter@amd.com pTable->map(vaddr, new_paddr, PageBytes, clobber); 3457487Ssteve.reinhardt@amd.com new_tc->getMemProxy().writeBlob(vaddr, buf_p, PageBytes); 34610930Sbrandon.potter@amd.com delete[] buf_p; 34710930Sbrandon.potter@amd.com} 34810930Sbrandon.potter@amd.com 34910930Sbrandon.potter@amd.combool 35010930Sbrandon.potter@amd.comProcess::fixupStackFault(Addr vaddr) 3515282Srstrong@cs.ucsd.edu{ 35210930Sbrandon.potter@amd.com Addr stack_min = memState->getStackMin(); 3535282Srstrong@cs.ucsd.edu Addr stack_base = memState->getStackBase(); 35410930Sbrandon.potter@amd.com Addr max_stack_size = memState->getMaxStackSize(); 35510930Sbrandon.potter@amd.com 35610932Sbrandon.potter@amd.com // Check if this is already on the stack and there's just no page there 35711785Sjthestness@gmail.com // yet. 35811785Sjthestness@gmail.com if (vaddr >= stack_min && vaddr < stack_base) { 35911785Sjthestness@gmail.com allocateMem(roundDown(vaddr, PageBytes), PageBytes); 36011785Sjthestness@gmail.com return true; 36111785Sjthestness@gmail.com } 36211785Sjthestness@gmail.com 36311785Sjthestness@gmail.com // We've accessed the next page of the stack, so extend it to include 36411785Sjthestness@gmail.com // this address. 36511785Sjthestness@gmail.com if (vaddr < stack_min && vaddr >= stack_base - max_stack_size) { 36611785Sjthestness@gmail.com while (vaddr < stack_min) { 36711785Sjthestness@gmail.com stack_min -= TheISA::PageBytes; 36811785Sjthestness@gmail.com if (stack_base - stack_min > max_stack_size) 36910930Sbrandon.potter@amd.com fatal("Maximum stack size exceeded\n"); 37010930Sbrandon.potter@amd.com allocateMem(stack_min, TheISA::PageBytes); 37110930Sbrandon.potter@amd.com inform("Increasing stack size by one page."); 37210930Sbrandon.potter@amd.com } 37310930Sbrandon.potter@amd.com memState->setStackMin(stack_min); 3745282Srstrong@cs.ucsd.edu return true; 3755282Srstrong@cs.ucsd.edu } 37610930Sbrandon.potter@amd.com return false; 37710930Sbrandon.potter@amd.com} 37810932Sbrandon.potter@amd.com 37911785Sjthestness@gmail.comvoid 38011785Sjthestness@gmail.comProcess::serialize(CheckpointOut &cp) const 38111785Sjthestness@gmail.com{ 38211785Sjthestness@gmail.com memState->serialize(cp); 38311785Sjthestness@gmail.com pTable->serialize(cp); 38411785Sjthestness@gmail.com /** 38511785Sjthestness@gmail.com * Checkpoints for file descriptors currently do not work. Need to 38611785Sjthestness@gmail.com * come back and fix them at a later date. 38711785Sjthestness@gmail.com */ 38811785Sjthestness@gmail.com 38911785Sjthestness@gmail.com warn("Checkpoints for file descriptors currently do not work."); 39011785Sjthestness@gmail.com#if 0 39110930Sbrandon.potter@amd.com for (int x = 0; x < fds->getSize(); x++) 39210930Sbrandon.potter@amd.com (*fds)[x].serializeSection(cp, csprintf("FDEntry%d", x)); 39310930Sbrandon.potter@amd.com#endif 39410930Sbrandon.potter@amd.com 39510930Sbrandon.potter@amd.com} 3965282Srstrong@cs.ucsd.edu 3975282Srstrong@cs.ucsd.eduvoid 39810932Sbrandon.potter@amd.comProcess::unserialize(CheckpointIn &cp) 39911785Sjthestness@gmail.com{ 40011785Sjthestness@gmail.com memState->unserialize(cp); 40111785Sjthestness@gmail.com pTable->unserialize(cp); 40211785Sjthestness@gmail.com /** 40311785Sjthestness@gmail.com * Checkpoints for file descriptors currently do not work. Need to 40411785Sjthestness@gmail.com * come back and fix them at a later date. 40511785Sjthestness@gmail.com */ 40611785Sjthestness@gmail.com warn("Checkpoints for file descriptors currently do not work."); 40711785Sjthestness@gmail.com#if 0 40811785Sjthestness@gmail.com for (int x = 0; x < fds->getSize(); x++) 40911785Sjthestness@gmail.com (*fds)[x]->unserializeSection(cp, csprintf("FDEntry%d", x)); 41011785Sjthestness@gmail.com fds->restoreFileOffsets(); 41110930Sbrandon.potter@amd.com#endif 41210930Sbrandon.potter@amd.com // The above returns a bool so that you could do something if you don't 41310930Sbrandon.potter@amd.com // find the param in the checkpoint if you wanted to, like set a default 41410930Sbrandon.potter@amd.com // but in this case we'll just stick with the instantiated value if not 41510930Sbrandon.potter@amd.com // found. 41610930Sbrandon.potter@amd.com} 41710930Sbrandon.potter@amd.com 41810930Sbrandon.potter@amd.combool 4195514SMichael.Adler@intel.comProcess::map(Addr vaddr, Addr paddr, int size, bool cacheable) 4205282Srstrong@cs.ucsd.edu{ 42110930Sbrandon.potter@amd.com pTable->map(vaddr, paddr, size, 42210932Sbrandon.potter@amd.com cacheable ? EmulationPageTable::MappingFlags(0) : 42310930Sbrandon.potter@amd.com EmulationPageTable::Uncacheable); 42410930Sbrandon.potter@amd.com return true; 4255282Srstrong@cs.ucsd.edu} 42610930Sbrandon.potter@amd.com 42710930Sbrandon.potter@amd.comvoid 42810930Sbrandon.potter@amd.comProcess::syscall(int64_t callnum, ThreadContext *tc, Fault *fault) 42910930Sbrandon.potter@amd.com{ 4305282Srstrong@cs.ucsd.edu numSyscalls++; 43110930Sbrandon.potter@amd.com 43210930Sbrandon.potter@amd.com SyscallDesc *desc = getDesc(callnum); 43310930Sbrandon.potter@amd.com if (desc == nullptr) 4345282Srstrong@cs.ucsd.edu fatal("Syscall %d out of range", callnum); 43510930Sbrandon.potter@amd.com 4365282Srstrong@cs.ucsd.edu desc->doSyscall(callnum, this, tc, fault); 43710932Sbrandon.potter@amd.com} 43811378Sbrandon.potter@amd.com 43910930Sbrandon.potter@amd.comRegVal 44010930Sbrandon.potter@amd.comProcess::getSyscallArg(ThreadContext *tc, int &i, int width) 44110930Sbrandon.potter@amd.com{ 44210930Sbrandon.potter@amd.com return getSyscallArg(tc, i); 4435282Srstrong@cs.ucsd.edu} 4445282Srstrong@cs.ucsd.edu 4455282Srstrong@cs.ucsd.eduEmulatedDriver * 4467487Ssteve.reinhardt@amd.comProcess::findDriver(std::string filename) 4475282Srstrong@cs.ucsd.edu{ 44810932Sbrandon.potter@amd.com for (EmulatedDriver *d : drivers) { 4497487Ssteve.reinhardt@amd.com if (d->match(filename)) 45010930Sbrandon.potter@amd.com return d; 45110930Sbrandon.potter@amd.com } 45210930Sbrandon.potter@amd.com 4535282Srstrong@cs.ucsd.edu return nullptr; 4545282Srstrong@cs.ucsd.edu} 4555282Srstrong@cs.ucsd.edu 4565282Srstrong@cs.ucsd.edustd::string 4577487Ssteve.reinhardt@amd.comProcess::checkPathRedirect(const std::string &filename) 4587487Ssteve.reinhardt@amd.com{ 45910932Sbrandon.potter@amd.com // If the input parameter contains a relative path, convert it. Note, 46010930Sbrandon.potter@amd.com // the return value for this method should always return an absolute 46110930Sbrandon.potter@amd.com // path on the host filesystem. The return value will be used to 4625282Srstrong@cs.ucsd.edu // open and manipulate the path specified by the input parameter. Since 4635282Srstrong@cs.ucsd.edu // all filesystem handling in syscall mode is passed through to the host, 4643311Ssaidi@eecs.umich.edu // we deal only with host paths. 46510905Sandreas.sandberg@arm.com auto host_fs_abs_path = absolutePath(filename, true); 4663311Ssaidi@eecs.umich.edu 4673311Ssaidi@eecs.umich.edu for (auto path : system->redirectPaths) { 4683311Ssaidi@eecs.umich.edu // Search through the redirect paths to see if a starting substring of 4693311Ssaidi@eecs.umich.edu // our path falls into any buckets which need to redirected. 4703311Ssaidi@eecs.umich.edu if (startswith(host_fs_abs_path, path->appPath())) { 4713311Ssaidi@eecs.umich.edu std::string tail = host_fs_abs_path.substr(path->appPath().size()); 4723311Ssaidi@eecs.umich.edu 4733311Ssaidi@eecs.umich.edu // If this path needs to be redirected, search through a list 4743311Ssaidi@eecs.umich.edu // of targets to see if we can match a valid file (or directory). 47510905Sandreas.sandberg@arm.com for (auto host_path : path->hostPaths()) { 47610930Sbrandon.potter@amd.com if (access((host_path + tail).c_str(), R_OK) == 0) { 47710930Sbrandon.potter@amd.com // Return the valid match. 4785282Srstrong@cs.ucsd.edu return host_path + tail; 4793311Ssaidi@eecs.umich.edu } 4803311Ssaidi@eecs.umich.edu } 4813311Ssaidi@eecs.umich.edu // The path needs to be redirected, but the file or directory 4823311Ssaidi@eecs.umich.edu // does not exist on the host filesystem. Return the first 48310905Sandreas.sandberg@arm.com // host path as a default. 4843311Ssaidi@eecs.umich.edu return path->hostPaths()[0] + tail; 4853311Ssaidi@eecs.umich.edu } 4863311Ssaidi@eecs.umich.edu } 4873311Ssaidi@eecs.umich.edu 4883311Ssaidi@eecs.umich.edu // The path does not need to be redirected. 4893311Ssaidi@eecs.umich.edu return host_fs_abs_path; 4903311Ssaidi@eecs.umich.edu} 4913311Ssaidi@eecs.umich.edu 4923311Ssaidi@eecs.umich.eduvoid 49310905Sandreas.sandberg@arm.comProcess::updateBias() 49410930Sbrandon.potter@amd.com{ 49510932Sbrandon.potter@amd.com ObjectFile *interp = objFile->getInterpreter(); 49610930Sbrandon.potter@amd.com 4977487Ssteve.reinhardt@amd.com if (!interp || !interp->relocatable()) 49810932Sbrandon.potter@amd.com return; 4996820SLisa.Hsu@amd.com 5006820SLisa.Hsu@amd.com // Determine how large the interpreters footprint will be in the process 50110930Sbrandon.potter@amd.com // address space. 50210929Sbrandon.potter@amd.com Addr interp_mapsize = roundUp(interp->mapSize(), TheISA::PageBytes); 5033311Ssaidi@eecs.umich.edu 5042SN/A // We are allocating the memory area; set the bias to the lowest address 5052SN/A // in the allocated memory region. 5069110Ssteve.reinhardt@amd.com Addr mmap_end = memState->getMmapEnd(); 50710558Salexandru.dutu@amd.com Addr ld_bias = mmapGrowsDown() ? mmap_end - interp_mapsize : mmap_end; 5089110Ssteve.reinhardt@amd.com 50910558Salexandru.dutu@amd.com // Adjust the process mmap area to give the interpreter room; the real 51011294Sandreas.hansson@arm.com // execve system call would just invoke the kernel's internal mmap 5119110Ssteve.reinhardt@amd.com // functions to make these adjustments. 5129110Ssteve.reinhardt@amd.com mmap_end = mmapGrowsDown() ? ld_bias : mmap_end + interp_mapsize; 5139110Ssteve.reinhardt@amd.com memState->setMmapEnd(mmap_end); 5149110Ssteve.reinhardt@amd.com 5152378SN/A interp->updateBias(ld_bias); 51611851Sbrandon.potter@amd.com} 5172093SN/A 5182093SN/AObjectFile * 5192093SN/AProcess::getInterpreter() 5202093SN/A{ 5212093SN/A return objFile->getInterpreter(); 5222093SN/A} 5232093SN/A 5242680Sktlim@umich.eduAddr 5252093SN/AProcess::getBias() 5262SN/A{ 5276701Sgblack@eecs.umich.edu ObjectFile *interp = getInterpreter(); 52811851Sbrandon.potter@amd.com 5296701Sgblack@eecs.umich.edu return interp ? interp->bias() : objFile->bias(); 5306701Sgblack@eecs.umich.edu} 5316701Sgblack@eecs.umich.edu 5326701Sgblack@eecs.umich.eduAddr 53310496Ssteve.reinhardt@amd.comProcess::getStartPC() 53410496Ssteve.reinhardt@amd.com{ 53511851Sbrandon.potter@amd.com ObjectFile *interp = getInterpreter(); 53610496Ssteve.reinhardt@amd.com 53710496Ssteve.reinhardt@amd.com return interp ? interp->entryPoint() : objFile->entryPoint(); 53810496Ssteve.reinhardt@amd.com} 53910496Ssteve.reinhardt@amd.com 54010496Ssteve.reinhardt@amd.comstd::string 54110496Ssteve.reinhardt@amd.comProcess::absolutePath(const std::string &filename, bool host_filesystem) 54210496Ssteve.reinhardt@amd.com{ 54310496Ssteve.reinhardt@amd.com if (filename.empty() || startswith(filename, "/")) 54410496Ssteve.reinhardt@amd.com return filename; 54511389Sbrandon.potter@amd.com 54611851Sbrandon.potter@amd.com // Verify that the current working directories are initialized properly. 54711389Sbrandon.potter@amd.com // These members should be set initially via params from 'Process.py', 54811389Sbrandon.potter@amd.com // although they may change over time depending on what the application 54911389Sbrandon.potter@amd.com // does during simulation. 55011389Sbrandon.potter@amd.com assert(!tgtCwd.empty()); 55111389Sbrandon.potter@amd.com assert(!hostCwd.empty()); 55211389Sbrandon.potter@amd.com 55311389Sbrandon.potter@amd.com // Construct the absolute path given the current working directory for 55411389Sbrandon.potter@amd.com // either the host filesystem or target filesystem. The distinction only 55511389Sbrandon.potter@amd.com // matters if filesystem redirection is utilized in the simulation. 55611389Sbrandon.potter@amd.com auto path_base = host_filesystem ? hostCwd : tgtCwd; 55711389Sbrandon.potter@amd.com 55811389Sbrandon.potter@amd.com // Add a trailing '/' if the current working directory did not have one. 55911389Sbrandon.potter@amd.com normalize(path_base); 56011389Sbrandon.potter@amd.com 56111389Sbrandon.potter@amd.com // Append the filename onto the current working path. 56211389Sbrandon.potter@amd.com auto absolute_path = path_base + filename; 56311389Sbrandon.potter@amd.com 56411389Sbrandon.potter@amd.com return absolute_path; 56511389Sbrandon.potter@amd.com} 56611389Sbrandon.potter@amd.com 56711389Sbrandon.potter@amd.comProcess * 56811389Sbrandon.potter@amd.comProcessParams::create() 56911389Sbrandon.potter@amd.com{ 57011392Sbrandon.potter@amd.com Process *process = nullptr; 57111851Sbrandon.potter@amd.com 57211392Sbrandon.potter@amd.com // If not specified, set the executable parameter equal to the 57311392Sbrandon.potter@amd.com // simulated system's zeroth command line parameter 57411392Sbrandon.potter@amd.com if (executable == "") { 57511392Sbrandon.potter@amd.com executable = cmd[0]; 57611392Sbrandon.potter@amd.com } 57711389Sbrandon.potter@amd.com 57811851Sbrandon.potter@amd.com ObjectFile *obj_file = createObjectFile(executable); 57911389Sbrandon.potter@amd.com if (obj_file == nullptr) { 58011392Sbrandon.potter@amd.com fatal("Can't load object file %s", executable); 58111389Sbrandon.potter@amd.com } 58211389Sbrandon.potter@amd.com 58311389Sbrandon.potter@amd.com#if THE_ISA == ALPHA_ISA 58411389Sbrandon.potter@amd.com if (obj_file->getArch() != ObjectFile::Alpha) 58511389Sbrandon.potter@amd.com fatal("Object file architecture does not match compiled ISA (Alpha)."); 58611389Sbrandon.potter@amd.com 58711851Sbrandon.potter@amd.com switch (obj_file->getOpSys()) { 58811389Sbrandon.potter@amd.com case ObjectFile::UnknownOpSys: 58911392Sbrandon.potter@amd.com warn("Unknown operating system; assuming Linux."); 59011389Sbrandon.potter@amd.com // fall through 59111389Sbrandon.potter@amd.com case ObjectFile::Linux: 59211389Sbrandon.potter@amd.com process = new AlphaLinuxProcess(this, obj_file); 59311389Sbrandon.potter@amd.com break; 59410496Ssteve.reinhardt@amd.com 59511851Sbrandon.potter@amd.com default: 59611851Sbrandon.potter@amd.com fatal("Unknown/unsupported operating system."); 5972715Sstever@eecs.umich.edu } 59811851Sbrandon.potter@amd.com#elif THE_ISA == SPARC_ISA 5992715Sstever@eecs.umich.edu if (obj_file->getArch() != ObjectFile::SPARC64 && 60011140Sjthestness@gmail.com obj_file->getArch() != ObjectFile::SPARC32) 60111140Sjthestness@gmail.com fatal("Object file architecture does not match compiled ISA (SPARC)."); 60211851Sbrandon.potter@amd.com switch (obj_file->getOpSys()) { 60311851Sbrandon.potter@amd.com case ObjectFile::UnknownOpSys: 60411140Sjthestness@gmail.com warn("Unknown operating system; assuming Linux."); 60511140Sjthestness@gmail.com // fall through 60611851Sbrandon.potter@amd.com case ObjectFile::Linux: 60711851Sbrandon.potter@amd.com if (obj_file->getArch() == ObjectFile::SPARC64) { 60811851Sbrandon.potter@amd.com process = new Sparc64LinuxProcess(this, obj_file); 6092715Sstever@eecs.umich.edu } else { 6102715Sstever@eecs.umich.edu process = new Sparc32LinuxProcess(this, obj_file); 6115089Sgblack@eecs.umich.edu } 61211851Sbrandon.potter@amd.com break; 6135753Ssteve.reinhardt@amd.com 6145753Ssteve.reinhardt@amd.com case ObjectFile::Solaris: 61511851Sbrandon.potter@amd.com process = new SparcSolarisProcess(this, obj_file); 6165753Ssteve.reinhardt@amd.com break; 6175753Ssteve.reinhardt@amd.com 6185753Ssteve.reinhardt@amd.com default: 6192715Sstever@eecs.umich.edu fatal("Unknown/unsupported operating system."); 62011851Sbrandon.potter@amd.com } 6212715Sstever@eecs.umich.edu#elif THE_ISA == X86_ISA 6222715Sstever@eecs.umich.edu if (obj_file->getArch() != ObjectFile::X86_64 && 6232715Sstever@eecs.umich.edu obj_file->getArch() != ObjectFile::I386) 6242715Sstever@eecs.umich.edu fatal("Object file architecture does not match compiled ISA (x86)."); 6252715Sstever@eecs.umich.edu switch (obj_file->getOpSys()) { 6262715Sstever@eecs.umich.edu case ObjectFile::UnknownOpSys: 62711851Sbrandon.potter@amd.com warn("Unknown operating system; assuming Linux."); 62811851Sbrandon.potter@amd.com // fall through 6292715Sstever@eecs.umich.edu case ObjectFile::Linux: 63011851Sbrandon.potter@amd.com if (obj_file->getArch() == ObjectFile::X86_64) { 6315753Ssteve.reinhardt@amd.com process = new X86_64LinuxProcess(this, obj_file); 6325753Ssteve.reinhardt@amd.com } else { 6335753Ssteve.reinhardt@amd.com process = new I386LinuxProcess(this, obj_file); 6342715Sstever@eecs.umich.edu } 63511851Sbrandon.potter@amd.com break; 63611851Sbrandon.potter@amd.com 6374111Sgblack@eecs.umich.edu default: 63811851Sbrandon.potter@amd.com fatal("Unknown/unsupported operating system."); 6394111Sgblack@eecs.umich.edu } 6402715Sstever@eecs.umich.edu#elif THE_ISA == MIPS_ISA 6412715Sstever@eecs.umich.edu if (obj_file->getArch() != ObjectFile::Mips) 6422715Sstever@eecs.umich.edu fatal("Object file architecture does not match compiled ISA (MIPS)."); 6432715Sstever@eecs.umich.edu switch (obj_file->getOpSys()) { 64411851Sbrandon.potter@amd.com case ObjectFile::UnknownOpSys: 6452715Sstever@eecs.umich.edu warn("Unknown operating system; assuming Linux."); 6465753Ssteve.reinhardt@amd.com // fall through 6472715Sstever@eecs.umich.edu case ObjectFile::Linux: 6482715Sstever@eecs.umich.edu process = new MipsLinuxProcess(this, obj_file); 6492715Sstever@eecs.umich.edu break; 6504157Sgblack@eecs.umich.edu 65111851Sbrandon.potter@amd.com default: 65211851Sbrandon.potter@amd.com fatal("Unknown/unsupported operating system."); 6534166Sgblack@eecs.umich.edu } 65411851Sbrandon.potter@amd.com#elif THE_ISA == ARM_ISA 6555753Ssteve.reinhardt@amd.com ObjectFile::Arch arch = obj_file->getArch(); 6565753Ssteve.reinhardt@amd.com if (arch != ObjectFile::Arm && arch != ObjectFile::Thumb && 6575753Ssteve.reinhardt@amd.com arch != ObjectFile::Arm64) 6584166Sgblack@eecs.umich.edu fatal("Object file architecture does not match compiled ISA (ARM)."); 65911851Sbrandon.potter@amd.com switch (obj_file->getOpSys()) { 66011851Sbrandon.potter@amd.com case ObjectFile::UnknownOpSys: 6615874Sgblack@eecs.umich.edu warn("Unknown operating system; assuming Linux."); 66211851Sbrandon.potter@amd.com // fall through 6635874Sgblack@eecs.umich.edu case ObjectFile::Linux: 6644166Sgblack@eecs.umich.edu if (arch == ObjectFile::Arm64) { 6655753Ssteve.reinhardt@amd.com process = new ArmLinuxProcess64(this, obj_file, 6664157Sgblack@eecs.umich.edu obj_file->getArch()); 6674157Sgblack@eecs.umich.edu } else { 6684157Sgblack@eecs.umich.edu process = new ArmLinuxProcess32(this, obj_file, 6692715Sstever@eecs.umich.edu obj_file->getArch()); 67011851Sbrandon.potter@amd.com } 6712715Sstever@eecs.umich.edu break; 67211851Sbrandon.potter@amd.com case ObjectFile::FreeBSD: 6735753Ssteve.reinhardt@amd.com if (arch == ObjectFile::Arm64) { 6745753Ssteve.reinhardt@amd.com process = new ArmFreebsdProcess64(this, obj_file, 6755753Ssteve.reinhardt@amd.com obj_file->getArch()); 6762715Sstever@eecs.umich.edu } else { 67711851Sbrandon.potter@amd.com process = new ArmFreebsdProcess32(this, obj_file, 6782715Sstever@eecs.umich.edu obj_file->getArch()); 6792715Sstever@eecs.umich.edu } 6802715Sstever@eecs.umich.edu break; 6812715Sstever@eecs.umich.edu case ObjectFile::LinuxArmOABI: 6822715Sstever@eecs.umich.edu fatal("M5 does not support ARM OABI binaries. Please recompile with an" 6835335Shines@cs.fsu.edu " EABI compiler."); 68411851Sbrandon.potter@amd.com default: 68510037SARM gem5 Developers fatal("Unknown/unsupported operating system."); 68610037SARM gem5 Developers } 6875335Shines@cs.fsu.edu#elif THE_ISA == POWER_ISA 68811851Sbrandon.potter@amd.com if (obj_file->getArch() != ObjectFile::Power) 6895753Ssteve.reinhardt@amd.com fatal("Object file architecture does not match compiled ISA (Power)."); 6905753Ssteve.reinhardt@amd.com switch (obj_file->getOpSys()) { 6915753Ssteve.reinhardt@amd.com case ObjectFile::UnknownOpSys: 6925335Shines@cs.fsu.edu warn("Unknown operating system; assuming Linux."); 69310037SARM gem5 Developers // fall through 69411851Sbrandon.potter@amd.com case ObjectFile::Linux: 69511851Sbrandon.potter@amd.com process = new PowerLinuxProcess(this, obj_file); 69610037SARM gem5 Developers break; 69711851Sbrandon.potter@amd.com 69811851Sbrandon.potter@amd.com default: 69910037SARM gem5 Developers fatal("Unknown/unsupported operating system."); 7005335Shines@cs.fsu.edu } 70110810Sbr@bsdpad.com#elif THE_ISA == RISCV_ISA 70210810Sbr@bsdpad.com ObjectFile::Arch arch = obj_file->getArch(); 70311851Sbrandon.potter@amd.com if (arch != ObjectFile::Riscv64 && arch != ObjectFile::Riscv32) 70411851Sbrandon.potter@amd.com fatal("Object file architecture does not match compiled ISA (RISCV)."); 70510810Sbr@bsdpad.com switch (obj_file->getOpSys()) { 70611851Sbrandon.potter@amd.com case ObjectFile::UnknownOpSys: 70711851Sbrandon.potter@amd.com warn("Unknown operating system; assuming Linux."); 70810810Sbr@bsdpad.com // fall through 70910810Sbr@bsdpad.com case ObjectFile::Linux: 7106392Ssaidi@eecs.umich.edu if (arch == ObjectFile::Riscv64) { 7116392Ssaidi@eecs.umich.edu process = new RiscvLinuxProcess64(this, obj_file); 7126392Ssaidi@eecs.umich.edu } else { 7135335Shines@cs.fsu.edu process = new RiscvLinuxProcess32(this, obj_file); 7145335Shines@cs.fsu.edu } 7155335Shines@cs.fsu.edu break; 7166691Stjones1@inf.ed.ac.uk default: 71711851Sbrandon.potter@amd.com fatal("Unknown/unsupported operating system."); 7186691Stjones1@inf.ed.ac.uk } 71911851Sbrandon.potter@amd.com#else 7206691Stjones1@inf.ed.ac.uk#error "THE_ISA not set" 7216691Stjones1@inf.ed.ac.uk#endif 7226691Stjones1@inf.ed.ac.uk 7236691Stjones1@inf.ed.ac.uk if (process == nullptr) 72411851Sbrandon.potter@amd.com fatal("Unknown error creating process object."); 7256691Stjones1@inf.ed.ac.uk return process; 7266691Stjones1@inf.ed.ac.uk} 7276691Stjones1@inf.ed.ac.uk