process.cc revision 11854
12SN/A/*
21762SN/A * Copyright (c) 2003-2004 The Regents of The University of Michigan
32SN/A * All rights reserved.
42SN/A *
52SN/A * Redistribution and use in source and binary forms, with or without
62SN/A * modification, are permitted provided that the following conditions are
72SN/A * met: redistributions of source code must retain the above copyright
82SN/A * notice, this list of conditions and the following disclaimer;
92SN/A * redistributions in binary form must reproduce the above copyright
102SN/A * notice, this list of conditions and the following disclaimer in the
112SN/A * documentation and/or other materials provided with the distribution;
122SN/A * neither the name of the copyright holders nor the names of its
132SN/A * contributors may be used to endorse or promote products derived from
142SN/A * this software without specific prior written permission.
152SN/A *
162SN/A * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
172SN/A * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
182SN/A * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
192SN/A * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
202SN/A * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
212SN/A * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
222SN/A * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
232SN/A * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
242SN/A * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
252SN/A * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
262SN/A * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
272665Ssaidi@eecs.umich.edu *
282665Ssaidi@eecs.umich.edu * Authors: Gabe Black
292665Ssaidi@eecs.umich.edu *          Ali Saidi
302665Ssaidi@eecs.umich.edu */
312665Ssaidi@eecs.umich.edu
322SN/A#include "arch/alpha/process.hh"
332SN/A
342SN/A#include "arch/alpha/isa_traits.hh"
352SN/A#include "base/loader/elf_object.hh"
3656SN/A#include "base/loader/object_file.hh"
371717SN/A#include "base/misc.hh"
382518SN/A#include "cpu/thread_context.hh"
3956SN/A#include "debug/Loader.hh"
404776Sgblack@eecs.umich.edu#include "mem/page_table.hh"
414762Snate@binkert.org#include "sim/aux_vector.hh"
423065Sgblack@eecs.umich.edu#include "sim/byteswap.hh"
432SN/A#include "sim/process_impl.hh"
442973Sgblack@eecs.umich.edu#include "sim/syscall_return.hh"
452SN/A#include "sim/system.hh"
463506Ssaidi@eecs.umich.edu
474054Sbinkertn@umich.eduusing namespace AlphaISA;
484054Sbinkertn@umich.eduusing namespace std;
495866Sksewell@umich.edu
505866Sksewell@umich.eduAlphaProcess::AlphaProcess(ProcessParams *params, ObjectFile *objFile)
515866Sksewell@umich.edu    : Process(params, objFile)
525866Sksewell@umich.edu{
535866Sksewell@umich.edu    brk_point = objFile->dataBase() + objFile->dataSize() + objFile->bssSize();
545866Sksewell@umich.edu    brk_point = roundUp(brk_point, PageBytes);
555784Sgblack@eecs.umich.edu
564054Sbinkertn@umich.edu    // Set up stack.  On Alpha, stack goes below text section.  This
574776Sgblack@eecs.umich.edu    // code should get moved to some architecture-specific spot.
584054Sbinkertn@umich.edu    stack_base = objFile->textBase() - (409600+4096);
594776Sgblack@eecs.umich.edu
605866Sksewell@umich.edu    // Set up region for mmaps.  Tru64 seems to start just above 0 and
614054Sbinkertn@umich.edu    // grow up from there.
624776Sgblack@eecs.umich.edu    mmap_end = 0x10000;
634054Sbinkertn@umich.edu
644776Sgblack@eecs.umich.edu    // Set pointer for next thread stack.  Reserve 8M for main stack.
654776Sgblack@eecs.umich.edu    next_thread_stack_base = stack_base - (8 * 1024 * 1024);
664054Sbinkertn@umich.edu
674776Sgblack@eecs.umich.edu}
685715Shsul@eecs.umich.edu
694776Sgblack@eecs.umich.eduvoid
704776Sgblack@eecs.umich.eduAlphaProcess::argsInit(int intSize, int pageSize)
714776Sgblack@eecs.umich.edu{
724776Sgblack@eecs.umich.edu    // Patch the ld_bias for dynamic executables.
734776Sgblack@eecs.umich.edu    updateBias();
744776Sgblack@eecs.umich.edu
754776Sgblack@eecs.umich.edu    objFile->loadSections(initVirtMem);
764776Sgblack@eecs.umich.edu
775784Sgblack@eecs.umich.edu    typedef AuxVector<uint64_t> auxv_t;
784776Sgblack@eecs.umich.edu    std::vector<auxv_t>  auxv;
794776Sgblack@eecs.umich.edu
805784Sgblack@eecs.umich.edu    ElfObject * elfObject = dynamic_cast<ElfObject *>(objFile);
814776Sgblack@eecs.umich.edu    if (elfObject)
824776Sgblack@eecs.umich.edu    {
835784Sgblack@eecs.umich.edu        // modern glibc uses a bunch of auxiliary vectors to set up
845784Sgblack@eecs.umich.edu        // TLS as well as do a bunch of other stuff
855784Sgblack@eecs.umich.edu        // these vectors go on the bottom of the stack, below argc/argv/envp
865784Sgblack@eecs.umich.edu        // pointers but above actual arg strings
875784Sgblack@eecs.umich.edu        // I don't have all the ones glibc looks at here, but so far it doesn't
885784Sgblack@eecs.umich.edu        // seem to be a problem.
895784Sgblack@eecs.umich.edu        // check out _dl_aux_init() in glibc/elf/dl-support.c for details
905784Sgblack@eecs.umich.edu        // --Lisa
914776Sgblack@eecs.umich.edu        auxv.push_back(auxv_t(M5_AT_PAGESZ, AlphaISA::PageBytes));
924776Sgblack@eecs.umich.edu        auxv.push_back(auxv_t(M5_AT_CLKTCK, 100));
934776Sgblack@eecs.umich.edu        auxv.push_back(auxv_t(M5_AT_PHDR, elfObject->programHeaderTable()));
944776Sgblack@eecs.umich.edu        DPRINTF(Loader, "auxv at PHDR %08p\n", elfObject->programHeaderTable());
954776Sgblack@eecs.umich.edu        auxv.push_back(auxv_t(M5_AT_PHNUM, elfObject->programHeaderCount()));
965784Sgblack@eecs.umich.edu        // This is the base address of the ELF interpreter; it should be
974776Sgblack@eecs.umich.edu        // zero for static executables or contain the base address for
985784Sgblack@eecs.umich.edu        // dynamic executables.
995784Sgblack@eecs.umich.edu        auxv.push_back(auxv_t(M5_AT_BASE, getBias()));
1005784Sgblack@eecs.umich.edu        auxv.push_back(auxv_t(M5_AT_ENTRY, objFile->entryPoint()));
1015784Sgblack@eecs.umich.edu        auxv.push_back(auxv_t(M5_AT_UID, uid()));
1025784Sgblack@eecs.umich.edu        auxv.push_back(auxv_t(M5_AT_EUID, euid()));
1035784Sgblack@eecs.umich.edu        auxv.push_back(auxv_t(M5_AT_GID, gid()));
1045784Sgblack@eecs.umich.edu        auxv.push_back(auxv_t(M5_AT_EGID, egid()));
1055784Sgblack@eecs.umich.edu
1065784Sgblack@eecs.umich.edu    }
1075784Sgblack@eecs.umich.edu
1085784Sgblack@eecs.umich.edu    // Calculate how much space we need for arg & env & auxv arrays.
1095784Sgblack@eecs.umich.edu    int argv_array_size = intSize * (argv.size() + 1);
1105784Sgblack@eecs.umich.edu    int envp_array_size = intSize * (envp.size() + 1);
1115784Sgblack@eecs.umich.edu    int auxv_array_size = intSize * 2 * (auxv.size() + 1);
1125784Sgblack@eecs.umich.edu
1135784Sgblack@eecs.umich.edu    int arg_data_size = 0;
1145784Sgblack@eecs.umich.edu    for (vector<string>::size_type i = 0; i < argv.size(); ++i) {
1155784Sgblack@eecs.umich.edu        arg_data_size += argv[i].size() + 1;
1165784Sgblack@eecs.umich.edu    }
1174776Sgblack@eecs.umich.edu    int env_data_size = 0;
1184776Sgblack@eecs.umich.edu    for (vector<string>::size_type i = 0; i < envp.size(); ++i) {
1194776Sgblack@eecs.umich.edu        env_data_size += envp[i].size() + 1;
1204776Sgblack@eecs.umich.edu    }
1214776Sgblack@eecs.umich.edu
1224776Sgblack@eecs.umich.edu    int space_needed =
1233506Ssaidi@eecs.umich.edu        argv_array_size +
1243506Ssaidi@eecs.umich.edu        envp_array_size +
1255784Sgblack@eecs.umich.edu        auxv_array_size +
1265784Sgblack@eecs.umich.edu        arg_data_size +
1275784Sgblack@eecs.umich.edu        env_data_size;
1285784Sgblack@eecs.umich.edu
1295784Sgblack@eecs.umich.edu    if (space_needed < 32*1024)
1305784Sgblack@eecs.umich.edu        space_needed = 32*1024;
1315784Sgblack@eecs.umich.edu
1325784Sgblack@eecs.umich.edu    // set bottom of stack
1335784Sgblack@eecs.umich.edu    stack_min = stack_base - space_needed;
1345784Sgblack@eecs.umich.edu    // align it
1355784Sgblack@eecs.umich.edu    stack_min = roundDown(stack_min, pageSize);
1365784Sgblack@eecs.umich.edu    stack_size = stack_base - stack_min;
1375791Srstrong@cs.ucsd.edu    // map memory
1385784Sgblack@eecs.umich.edu    allocateMem(stack_min, roundUp(stack_size, pageSize));
1395784Sgblack@eecs.umich.edu
1405791Srstrong@cs.ucsd.edu    // map out initial stack contents
1415784Sgblack@eecs.umich.edu    Addr argv_array_base = stack_min + intSize; // room for argc
1425784Sgblack@eecs.umich.edu    Addr envp_array_base = argv_array_base + argv_array_size;
1435784Sgblack@eecs.umich.edu    Addr auxv_array_base = envp_array_base + envp_array_size;
1445784Sgblack@eecs.umich.edu    Addr arg_data_base = auxv_array_base + auxv_array_size;
1455784Sgblack@eecs.umich.edu    Addr env_data_base = arg_data_base + arg_data_size;
1465784Sgblack@eecs.umich.edu
1475784Sgblack@eecs.umich.edu    // write contents to stack
1484776Sgblack@eecs.umich.edu    uint64_t argc = argv.size();
1494776Sgblack@eecs.umich.edu    if (intSize == 8)
1502SN/A        argc = htog((uint64_t)argc);
1512SN/A    else if (intSize == 4)
1524776Sgblack@eecs.umich.edu        argc = htog((uint32_t)argc);
1532SN/A    else
1544776Sgblack@eecs.umich.edu        panic("Unknown int size");
1554776Sgblack@eecs.umich.edu
1563748Sgblack@eecs.umich.edu    initVirtMem.writeBlob(stack_min, (uint8_t*)&argc, intSize);
1575034Smilesck@eecs.umich.edu
1584776Sgblack@eecs.umich.edu    copyStringArray(argv, argv_array_base, arg_data_base, initVirtMem);
159    copyStringArray(envp, envp_array_base, env_data_base, initVirtMem);
160
161    //Copy the aux stuff
162    for (vector<auxv_t>::size_type x = 0; x < auxv.size(); x++) {
163        initVirtMem.writeBlob(auxv_array_base + x * 2 * intSize,
164                (uint8_t*)&(auxv[x].a_type), intSize);
165        initVirtMem.writeBlob(auxv_array_base + (x * 2 + 1) * intSize,
166                (uint8_t*)&(auxv[x].a_val), intSize);
167    }
168
169    ThreadContext *tc = system->getThreadContext(contextIds[0]);
170
171    setSyscallArg(tc, 0, argc);
172    setSyscallArg(tc, 1, argv_array_base);
173    tc->setIntReg(StackPointerReg, stack_min);
174
175    tc->pcState(getStartPC());
176}
177
178void
179AlphaProcess::setupASNReg()
180{
181    ThreadContext *tc = system->getThreadContext(contextIds[0]);
182    tc->setMiscRegNoEffect(IPR_DTB_ASN, _pid << 57);
183}
184
185
186void
187AlphaProcess::loadState(CheckpointIn &cp)
188{
189    Process::loadState(cp);
190    // need to set up ASN after unserialization since _pid value may
191    // come from checkpoint
192    setupASNReg();
193}
194
195
196void
197AlphaProcess::initState()
198{
199    // need to set up ASN before further initialization since init
200    // will involve writing to virtual memory addresses
201    setupASNReg();
202
203    Process::initState();
204
205    argsInit(MachineBytes, PageBytes);
206
207    ThreadContext *tc = system->getThreadContext(contextIds[0]);
208    tc->setIntReg(GlobalPointerReg, objFile->globalPointer());
209    //Operate in user mode
210    tc->setMiscRegNoEffect(IPR_ICM, mode_user << 3);
211    tc->setMiscRegNoEffect(IPR_DTB_CM, mode_user << 3);
212    //No super page mapping
213    tc->setMiscRegNoEffect(IPR_MCSR, 0);
214}
215
216AlphaISA::IntReg
217AlphaProcess::getSyscallArg(ThreadContext *tc, int &i)
218{
219    assert(i < 6);
220    return tc->readIntReg(FirstArgumentReg + i++);
221}
222
223void
224AlphaProcess::setSyscallArg(ThreadContext *tc, int i, AlphaISA::IntReg val)
225{
226    assert(i < 6);
227    tc->setIntReg(FirstArgumentReg + i, val);
228}
229
230void
231AlphaProcess::setSyscallReturn(ThreadContext *tc, SyscallReturn sysret)
232{
233    // check for error condition.  Alpha syscall convention is to
234    // indicate success/failure in reg a3 (r19) and put the
235    // return value itself in the standard return value reg (v0).
236    if (sysret.successful()) {
237        // no error
238        tc->setIntReg(SyscallSuccessReg, 0);
239        tc->setIntReg(ReturnValueReg, sysret.returnValue());
240    } else {
241        // got an error, return details
242        tc->setIntReg(SyscallSuccessReg, (IntReg)-1);
243        tc->setIntReg(ReturnValueReg, sysret.errnoValue());
244    }
245}
246