process.cc revision 12441
14123Sbinkertn@umich.edu/*
24123Sbinkertn@umich.edu * Copyright (c) 2003-2004 The Regents of The University of Michigan
39983Sstever@gmail.com * All rights reserved.
49983Sstever@gmail.com *
54123Sbinkertn@umich.edu * Redistribution and use in source and binary forms, with or without
64123Sbinkertn@umich.edu * modification, are permitted provided that the following conditions are
74123Sbinkertn@umich.edu * met: redistributions of source code must retain the above copyright
84123Sbinkertn@umich.edu * notice, this list of conditions and the following disclaimer;
94123Sbinkertn@umich.edu * redistributions in binary form must reproduce the above copyright
104123Sbinkertn@umich.edu * notice, this list of conditions and the following disclaimer in the
114123Sbinkertn@umich.edu * documentation and/or other materials provided with the distribution;
124123Sbinkertn@umich.edu * neither the name of the copyright holders nor the names of its
134123Sbinkertn@umich.edu * contributors may be used to endorse or promote products derived from
144123Sbinkertn@umich.edu * this software without specific prior written permission.
154123Sbinkertn@umich.edu *
164123Sbinkertn@umich.edu * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
174123Sbinkertn@umich.edu * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
184123Sbinkertn@umich.edu * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
194123Sbinkertn@umich.edu * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
204123Sbinkertn@umich.edu * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
214123Sbinkertn@umich.edu * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
224123Sbinkertn@umich.edu * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
234123Sbinkertn@umich.edu * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
244123Sbinkertn@umich.edu * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
254123Sbinkertn@umich.edu * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
264123Sbinkertn@umich.edu * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
274123Sbinkertn@umich.edu *
284123Sbinkertn@umich.edu * Authors: Gabe Black
294123Sbinkertn@umich.edu *          Ali Saidi
304123Sbinkertn@umich.edu */
314123Sbinkertn@umich.edu
324123Sbinkertn@umich.edu#include "arch/alpha/process.hh"
334123Sbinkertn@umich.edu
349983Sstever@gmail.com#include "arch/alpha/isa_traits.hh"
359983Sstever@gmail.com#include "base/loader/elf_object.hh"
369983Sstever@gmail.com#include "base/loader/object_file.hh"
374123Sbinkertn@umich.edu#include "base/logging.hh"
384123Sbinkertn@umich.edu#include "cpu/thread_context.hh"
396216Snate@binkert.org#include "debug/Loader.hh"
404123Sbinkertn@umich.edu#include "mem/page_table.hh"
419356Snilay@cs.wisc.edu#include "params/Process.hh"
424123Sbinkertn@umich.edu#include "sim/aux_vector.hh"
434123Sbinkertn@umich.edu#include "sim/byteswap.hh"
444123Sbinkertn@umich.edu#include "sim/process_impl.hh"
456216Snate@binkert.org#include "sim/syscall_return.hh"
464123Sbinkertn@umich.edu#include "sim/system.hh"
479983Sstever@gmail.com
489983Sstever@gmail.comusing namespace AlphaISA;
499983Sstever@gmail.comusing namespace std;
509983Sstever@gmail.com
519983Sstever@gmail.comAlphaProcess::AlphaProcess(ProcessParams *params, ObjectFile *objFile)
529983Sstever@gmail.com    : Process(params, new FuncPageTable(params->name, params->pid, PageBytes),
539983Sstever@gmail.com      objFile)
549983Sstever@gmail.com{
559983Sstever@gmail.com    fatal_if(params->useArchPT, "Arch page tables not implemented.");
569983Sstever@gmail.com    Addr brk_point = objFile->dataBase() + objFile->dataSize() +
579983Sstever@gmail.com                     objFile->bssSize();
589983Sstever@gmail.com    brk_point = roundUp(brk_point, PageBytes);
599983Sstever@gmail.com
609983Sstever@gmail.com    // Set up stack.  On Alpha, stack goes below text section.  This
619983Sstever@gmail.com    // code should get moved to some architecture-specific spot.
629983Sstever@gmail.com    Addr stack_base = objFile->textBase() - (409600+4096);
639983Sstever@gmail.com
649983Sstever@gmail.com    // Set up region for mmaps.
659983Sstever@gmail.com    Addr mmap_end = 0x10000;
669983Sstever@gmail.com
679983Sstever@gmail.com    Addr max_stack_size = 8 * 1024 * 1024;
689983Sstever@gmail.com
699983Sstever@gmail.com    // Set pointer for next thread stack.  Reserve 8M for main stack.
709983Sstever@gmail.com    Addr next_thread_stack_base = stack_base - max_stack_size;
719983Sstever@gmail.com
729983Sstever@gmail.com    memState = make_shared<MemState>(brk_point, stack_base, max_stack_size,
739983Sstever@gmail.com                                     next_thread_stack_base, mmap_end);
744123Sbinkertn@umich.edu}
754123Sbinkertn@umich.edu
764123Sbinkertn@umich.eduvoid
774123Sbinkertn@umich.eduAlphaProcess::argsInit(int intSize, int pageSize)
784123Sbinkertn@umich.edu{
799983Sstever@gmail.com    // Patch the ld_bias for dynamic executables.
804123Sbinkertn@umich.edu    updateBias();
814123Sbinkertn@umich.edu
829983Sstever@gmail.com    objFile->loadSections(initVirtMem);
839983Sstever@gmail.com
849983Sstever@gmail.com    typedef AuxVector<uint64_t> auxv_t;
859983Sstever@gmail.com    std::vector<auxv_t>  auxv;
869983Sstever@gmail.com
879983Sstever@gmail.com    ElfObject * elfObject = dynamic_cast<ElfObject *>(objFile);
889983Sstever@gmail.com    if (elfObject)
899983Sstever@gmail.com    {
909983Sstever@gmail.com        // modern glibc uses a bunch of auxiliary vectors to set up
919983Sstever@gmail.com        // TLS as well as do a bunch of other stuff
929983Sstever@gmail.com        // these vectors go on the bottom of the stack, below argc/argv/envp
939983Sstever@gmail.com        // pointers but above actual arg strings
949983Sstever@gmail.com        // I don't have all the ones glibc looks at here, but so far it doesn't
959983Sstever@gmail.com        // seem to be a problem.
969983Sstever@gmail.com        // check out _dl_aux_init() in glibc/elf/dl-support.c for details
979983Sstever@gmail.com        // --Lisa
989983Sstever@gmail.com        auxv.push_back(auxv_t(M5_AT_PAGESZ, AlphaISA::PageBytes));
999983Sstever@gmail.com        auxv.push_back(auxv_t(M5_AT_CLKTCK, 100));
1009983Sstever@gmail.com        auxv.push_back(auxv_t(M5_AT_PHDR, elfObject->programHeaderTable()));
1017823Ssteve.reinhardt@amd.com        DPRINTF(Loader, "auxv at PHDR %08p\n", elfObject->programHeaderTable());
1024123Sbinkertn@umich.edu        auxv.push_back(auxv_t(M5_AT_PHNUM, elfObject->programHeaderCount()));
1039174Satgutier@umich.edu        // This is the base address of the ELF interpreter; it should be
1049174Satgutier@umich.edu        // zero for static executables or contain the base address for
1059174Satgutier@umich.edu        // dynamic executables.
1064123Sbinkertn@umich.edu        auxv.push_back(auxv_t(M5_AT_BASE, getBias()));
1074123Sbinkertn@umich.edu        auxv.push_back(auxv_t(M5_AT_ENTRY, objFile->entryPoint()));
1089983Sstever@gmail.com        auxv.push_back(auxv_t(M5_AT_UID, uid()));
1099983Sstever@gmail.com        auxv.push_back(auxv_t(M5_AT_EUID, euid()));
1109983Sstever@gmail.com        auxv.push_back(auxv_t(M5_AT_GID, gid()));
1119983Sstever@gmail.com        auxv.push_back(auxv_t(M5_AT_EGID, egid()));
1129983Sstever@gmail.com
1139983Sstever@gmail.com    }
1149983Sstever@gmail.com
1159983Sstever@gmail.com    // Calculate how much space we need for arg & env & auxv arrays.
1169983Sstever@gmail.com    int argv_array_size = intSize * (argv.size() + 1);
1179983Sstever@gmail.com    int envp_array_size = intSize * (envp.size() + 1);
1189983Sstever@gmail.com    int auxv_array_size = intSize * 2 * (auxv.size() + 1);
1199983Sstever@gmail.com
1209983Sstever@gmail.com    int arg_data_size = 0;
1219983Sstever@gmail.com    for (vector<string>::size_type i = 0; i < argv.size(); ++i) {
1229983Sstever@gmail.com        arg_data_size += argv[i].size() + 1;
1239983Sstever@gmail.com    }
1249983Sstever@gmail.com    int env_data_size = 0;
1259983Sstever@gmail.com    for (vector<string>::size_type i = 0; i < envp.size(); ++i) {
1269983Sstever@gmail.com        env_data_size += envp[i].size() + 1;
1279983Sstever@gmail.com    }
1289983Sstever@gmail.com
1299983Sstever@gmail.com    int space_needed =
1309983Sstever@gmail.com        argv_array_size +
1319983Sstever@gmail.com        envp_array_size +
1329983Sstever@gmail.com        auxv_array_size +
1339983Sstever@gmail.com        arg_data_size +
1349983Sstever@gmail.com        env_data_size;
1359983Sstever@gmail.com
1369983Sstever@gmail.com    if (space_needed < 32*1024)
1379983Sstever@gmail.com        space_needed = 32*1024;
1389983Sstever@gmail.com
1399983Sstever@gmail.com    // set bottom of stack
1409983Sstever@gmail.com    memState->setStackMin(memState->getStackBase() - space_needed);
1419983Sstever@gmail.com    // align it
1429983Sstever@gmail.com    memState->setStackMin(roundDown(memState->getStackMin(), pageSize));
1439983Sstever@gmail.com    memState->setStackSize(memState->getStackBase() - memState->getStackMin());
1449983Sstever@gmail.com    // map memory
1459983Sstever@gmail.com    allocateMem(memState->getStackMin(), roundUp(memState->getStackSize(),
1469983Sstever@gmail.com                pageSize));
1479983Sstever@gmail.com
1489983Sstever@gmail.com    // map out initial stack contents
1499983Sstever@gmail.com    Addr argv_array_base = memState->getStackMin() + intSize; // room for argc
1509983Sstever@gmail.com    Addr envp_array_base = argv_array_base + argv_array_size;
1519983Sstever@gmail.com    Addr auxv_array_base = envp_array_base + envp_array_size;
1529983Sstever@gmail.com    Addr arg_data_base = auxv_array_base + auxv_array_size;
1539983Sstever@gmail.com    Addr env_data_base = arg_data_base + arg_data_size;
1549983Sstever@gmail.com
1559983Sstever@gmail.com    // write contents to stack
1569983Sstever@gmail.com    uint64_t argc = argv.size();
1579983Sstever@gmail.com    if (intSize == 8)
1589983Sstever@gmail.com        argc = htog((uint64_t)argc);
1599983Sstever@gmail.com    else if (intSize == 4)
1609983Sstever@gmail.com        argc = htog((uint32_t)argc);
1619983Sstever@gmail.com    else
1629983Sstever@gmail.com        panic("Unknown int size");
1639983Sstever@gmail.com
1649983Sstever@gmail.com    initVirtMem.writeBlob(memState->getStackMin(), (uint8_t*)&argc, intSize);
1659983Sstever@gmail.com
1669983Sstever@gmail.com    copyStringArray(argv, argv_array_base, arg_data_base, initVirtMem);
1679983Sstever@gmail.com    copyStringArray(envp, envp_array_base, env_data_base, initVirtMem);
1689983Sstever@gmail.com
1699983Sstever@gmail.com    //Copy the aux stuff
1709983Sstever@gmail.com    for (vector<auxv_t>::size_type x = 0; x < auxv.size(); x++) {
1719983Sstever@gmail.com        initVirtMem.writeBlob(auxv_array_base + x * 2 * intSize,
1729983Sstever@gmail.com                (uint8_t*)&(auxv[x].a_type), intSize);
1739983Sstever@gmail.com        initVirtMem.writeBlob(auxv_array_base + (x * 2 + 1) * intSize,
1749983Sstever@gmail.com                (uint8_t*)&(auxv[x].a_val), intSize);
1759983Sstever@gmail.com    }
1769983Sstever@gmail.com
1779983Sstever@gmail.com    ThreadContext *tc = system->getThreadContext(contextIds[0]);
1789983Sstever@gmail.com
1799983Sstever@gmail.com    setSyscallArg(tc, 0, argc);
1809983Sstever@gmail.com    setSyscallArg(tc, 1, argv_array_base);
1819983Sstever@gmail.com    tc->setIntReg(StackPointerReg, memState->getStackMin());
1829983Sstever@gmail.com
1839983Sstever@gmail.com    tc->pcState(getStartPC());
1849983Sstever@gmail.com}
1859983Sstever@gmail.com
1869983Sstever@gmail.comvoid
1874123Sbinkertn@umich.eduAlphaProcess::setupASNReg()
1884123Sbinkertn@umich.edu{
1894123Sbinkertn@umich.edu    ThreadContext *tc = system->getThreadContext(contextIds[0]);
1904123Sbinkertn@umich.edu    tc->setMiscRegNoEffect(IPR_DTB_ASN, _pid << 57);
1919983Sstever@gmail.com}
1929983Sstever@gmail.com
1934123Sbinkertn@umich.edu
1944123Sbinkertn@umich.eduvoid
1959983Sstever@gmail.comAlphaProcess::unserialize(CheckpointIn &cp)
1964123Sbinkertn@umich.edu{
1979983Sstever@gmail.com    Process::unserialize(cp);
1984123Sbinkertn@umich.edu    // need to set up ASN after unserialization since _pid value may
1994123Sbinkertn@umich.edu    // come from checkpoint
2009983Sstever@gmail.com    setupASNReg();
2014123Sbinkertn@umich.edu}
2024123Sbinkertn@umich.edu
2037822Ssteve.reinhardt@amd.com
2044123Sbinkertn@umich.eduvoid
2054123Sbinkertn@umich.eduAlphaProcess::initState()
2064123Sbinkertn@umich.edu{
2074123Sbinkertn@umich.edu    // need to set up ASN before further initialization since init
2084123Sbinkertn@umich.edu    // will involve writing to virtual memory addresses
2094123Sbinkertn@umich.edu    setupASNReg();
2104123Sbinkertn@umich.edu
2114123Sbinkertn@umich.edu    Process::initState();
2124123Sbinkertn@umich.edu
2134123Sbinkertn@umich.edu    argsInit(MachineBytes, PageBytes);
2144123Sbinkertn@umich.edu
2154123Sbinkertn@umich.edu    ThreadContext *tc = system->getThreadContext(contextIds[0]);
2164123Sbinkertn@umich.edu    tc->setIntReg(GlobalPointerReg, objFile->globalPointer());
2174123Sbinkertn@umich.edu    //Operate in user mode
2184123Sbinkertn@umich.edu    tc->setMiscRegNoEffect(IPR_ICM, mode_user << 3);
2194123Sbinkertn@umich.edu    tc->setMiscRegNoEffect(IPR_DTB_CM, mode_user << 3);
2204123Sbinkertn@umich.edu    //No super page mapping
2214123Sbinkertn@umich.edu    tc->setMiscRegNoEffect(IPR_MCSR, 0);
2224123Sbinkertn@umich.edu}
2234123Sbinkertn@umich.edu
2244123Sbinkertn@umich.eduAlphaISA::IntReg
2254123Sbinkertn@umich.eduAlphaProcess::getSyscallArg(ThreadContext *tc, int &i)
2264123Sbinkertn@umich.edu{
2274123Sbinkertn@umich.edu    assert(i < 6);
228    return tc->readIntReg(FirstArgumentReg + i++);
229}
230
231void
232AlphaProcess::setSyscallArg(ThreadContext *tc, int i, AlphaISA::IntReg val)
233{
234    assert(i < 6);
235    tc->setIntReg(FirstArgumentReg + i, val);
236}
237
238void
239AlphaProcess::setSyscallReturn(ThreadContext *tc, SyscallReturn sysret)
240{
241    // check for error condition.  Alpha syscall convention is to
242    // indicate success/failure in reg a3 (r19) and put the
243    // return value itself in the standard return value reg (v0).
244    if (sysret.successful()) {
245        // no error
246        tc->setIntReg(SyscallSuccessReg, 0);
247        tc->setIntReg(ReturnValueReg, sysret.returnValue());
248    } else {
249        // got an error, return details
250        tc->setIntReg(SyscallSuccessReg, (IntReg)-1);
251        tc->setIntReg(ReturnValueReg, sysret.errnoValue());
252    }
253}
254