process.cc revision 12441
114039Sstacze01@arm.com/*
214039Sstacze01@arm.com * Copyright (c) 2004-2005 The Regents of The University of Michigan
314039Sstacze01@arm.com * Copyright (c) 2016 The University of Virginia
414039Sstacze01@arm.com * All rights reserved.
514039Sstacze01@arm.com *
614039Sstacze01@arm.com * Redistribution and use in source and binary forms, with or without
714039Sstacze01@arm.com * modification, are permitted provided that the following conditions are
814039Sstacze01@arm.com * met: redistributions of source code must retain the above copyright
914039Sstacze01@arm.com * notice, this list of conditions and the following disclaimer;
1014039Sstacze01@arm.com * redistributions in binary form must reproduce the above copyright
1114039Sstacze01@arm.com * notice, this list of conditions and the following disclaimer in the
1214039Sstacze01@arm.com * documentation and/or other materials provided with the distribution;
1314039Sstacze01@arm.com * neither the name of the copyright holders nor the names of its
1414039Sstacze01@arm.com * contributors may be used to endorse or promote products derived from
1514039Sstacze01@arm.com * this software without specific prior written permission.
1614039Sstacze01@arm.com *
1714039Sstacze01@arm.com * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
1814039Sstacze01@arm.com * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
1914039Sstacze01@arm.com * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
2014039Sstacze01@arm.com * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
2114039Sstacze01@arm.com * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
2214039Sstacze01@arm.com * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
2314039Sstacze01@arm.com * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2414039Sstacze01@arm.com * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
2514039Sstacze01@arm.com * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2614039Sstacze01@arm.com * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
2714039Sstacze01@arm.com * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2814039Sstacze01@arm.com *
2914039Sstacze01@arm.com * Authors: Gabe Black
3014039Sstacze01@arm.com *          Ali Saidi
3114039Sstacze01@arm.com *          Korey Sewell
3214039Sstacze01@arm.com *          Alec Roelke
3314039Sstacze01@arm.com */
3414039Sstacze01@arm.com#include "arch/riscv/process.hh"
3514039Sstacze01@arm.com
3614039Sstacze01@arm.com#include <algorithm>
3714039Sstacze01@arm.com#include <cstddef>
3814039Sstacze01@arm.com#include <iostream>
3914039Sstacze01@arm.com#include <iterator>
4014039Sstacze01@arm.com#include <map>
4114039Sstacze01@arm.com#include <string>
4214039Sstacze01@arm.com#include <vector>
4314039Sstacze01@arm.com
4414039Sstacze01@arm.com#include "arch/riscv/isa_traits.hh"
4514039Sstacze01@arm.com#include "base/loader/elf_object.hh"
4614039Sstacze01@arm.com#include "base/loader/object_file.hh"
4714039Sstacze01@arm.com#include "base/logging.hh"
4814039Sstacze01@arm.com#include "base/random.hh"
4914039Sstacze01@arm.com#include "cpu/thread_context.hh"
5014039Sstacze01@arm.com#include "debug/Stack.hh"
5114039Sstacze01@arm.com#include "mem/page_table.hh"
5214039Sstacze01@arm.com#include "params/Process.hh"
5314039Sstacze01@arm.com#include "sim/aux_vector.hh"
5414039Sstacze01@arm.com#include "sim/process.hh"
5514039Sstacze01@arm.com#include "sim/process_impl.hh"
5614039Sstacze01@arm.com#include "sim/syscall_return.hh"
5714039Sstacze01@arm.com#include "sim/system.hh"
5814039Sstacze01@arm.com
5914039Sstacze01@arm.comusing namespace std;
6014039Sstacze01@arm.comusing namespace RiscvISA;
6114039Sstacze01@arm.com
6214039Sstacze01@arm.comRiscvProcess::RiscvProcess(ProcessParams *params, ObjectFile *objFile) :
6314039Sstacze01@arm.com        Process(params, new FuncPageTable(params->name, params->pid,
6414039Sstacze01@arm.com                                          PageBytes),
6514039Sstacze01@arm.com                objFile)
6614039Sstacze01@arm.com{
6714039Sstacze01@arm.com    fatal_if(params->useArchPT, "Arch page tables not implemented.");
6814039Sstacze01@arm.com    const Addr stack_base = 0x7FFFFFFFFFFFFFFFL;
6914039Sstacze01@arm.com    const Addr max_stack_size = 8 * 1024 * 1024;
7014039Sstacze01@arm.com    const Addr next_thread_stack_base = stack_base - max_stack_size;
7114039Sstacze01@arm.com    const Addr brk_point = roundUp(objFile->bssBase() + objFile->bssSize(),
7214039Sstacze01@arm.com            PageBytes);
7314039Sstacze01@arm.com    const Addr mmap_end = 0x4000000000000000L;
7414039Sstacze01@arm.com    memState = make_shared<MemState>(brk_point, stack_base, max_stack_size,
7514039Sstacze01@arm.com            next_thread_stack_base, mmap_end);
7614039Sstacze01@arm.com}
7714039Sstacze01@arm.com
7814039Sstacze01@arm.comvoid
7914039Sstacze01@arm.comRiscvProcess::initState()
8014039Sstacze01@arm.com{
8114039Sstacze01@arm.com    Process::initState();
8214039Sstacze01@arm.com
8314039Sstacze01@arm.com    argsInit<uint64_t>(PageBytes);
8414039Sstacze01@arm.com}
8514039Sstacze01@arm.com
8614039Sstacze01@arm.comtemplate<class IntType> void
8714039Sstacze01@arm.comRiscvProcess::argsInit(int pageSize)
8814039Sstacze01@arm.com{
8914039Sstacze01@arm.com    const int RandomBytes = 16;
9014039Sstacze01@arm.com
9114039Sstacze01@arm.com    updateBias();
9214039Sstacze01@arm.com    objFile->loadSections(initVirtMem);
9314039Sstacze01@arm.com    ElfObject* elfObject = dynamic_cast<ElfObject*>(objFile);
9414039Sstacze01@arm.com    memState->setStackMin(memState->getStackBase());
9514039Sstacze01@arm.com
9614039Sstacze01@arm.com    // Determine stack size and populate auxv
9714039Sstacze01@arm.com    Addr stack_top = memState->getStackMin();
9814039Sstacze01@arm.com    stack_top -= RandomBytes;
9914039Sstacze01@arm.com    for (const string& arg: argv)
10014039Sstacze01@arm.com        stack_top -= arg.size() + 1;
10114039Sstacze01@arm.com    for (const string& env: envp)
10214039Sstacze01@arm.com        stack_top -= env.size() + 1;
10314039Sstacze01@arm.com    stack_top &= -sizeof(Addr);
10414039Sstacze01@arm.com
10514039Sstacze01@arm.com    vector<AuxVector<IntType>> auxv;
10614039Sstacze01@arm.com    if (elfObject != nullptr) {
10714039Sstacze01@arm.com        auxv.push_back({M5_AT_ENTRY, objFile->entryPoint()});
10814039Sstacze01@arm.com        auxv.push_back({M5_AT_PHNUM, elfObject->programHeaderCount()});
10914039Sstacze01@arm.com        auxv.push_back({M5_AT_PHENT, elfObject->programHeaderSize()});
11014039Sstacze01@arm.com        auxv.push_back({M5_AT_PHDR, elfObject->programHeaderTable()});
11114039Sstacze01@arm.com        auxv.push_back({M5_AT_PAGESZ, PageBytes});
11214039Sstacze01@arm.com        auxv.push_back({M5_AT_SECURE, 0});
11314039Sstacze01@arm.com        auxv.push_back({M5_AT_RANDOM, stack_top});
11414039Sstacze01@arm.com        auxv.push_back({M5_AT_NULL, 0});
11514039Sstacze01@arm.com    }
11614039Sstacze01@arm.com    stack_top -= (1 + argv.size()) * sizeof(Addr) +
11714039Sstacze01@arm.com                   (1 + envp.size()) * sizeof(Addr) +
11814039Sstacze01@arm.com                   sizeof(Addr) + 2 * sizeof(IntType) * auxv.size();
11914039Sstacze01@arm.com    stack_top &= -2*sizeof(Addr);
12014039Sstacze01@arm.com    memState->setStackSize(memState->getStackBase() - stack_top);
12114039Sstacze01@arm.com    allocateMem(roundDown(stack_top, pageSize),
12214039Sstacze01@arm.com            roundUp(memState->getStackSize(), pageSize));
12314039Sstacze01@arm.com
12414039Sstacze01@arm.com    // Copy random bytes (for AT_RANDOM) to stack
12514100Sgiacomo.travaglini@arm.com    memState->setStackMin(memState->getStackMin() - RandomBytes);
12614039Sstacze01@arm.com    uint8_t at_random[RandomBytes];
12714039Sstacze01@arm.com    generate(begin(at_random), end(at_random),
12814039Sstacze01@arm.com             [&]{ return random_mt.random(0, 0xFF); });
12914039Sstacze01@arm.com    initVirtMem.writeBlob(memState->getStackMin(), at_random, RandomBytes);
13014039Sstacze01@arm.com
13114039Sstacze01@arm.com    // Copy argv to stack
13214039Sstacze01@arm.com    vector<Addr> argPointers;
13314039Sstacze01@arm.com    for (const string& arg: argv) {
13414039Sstacze01@arm.com        memState->setStackMin(memState->getStackMin() - (arg.size() + 1));
13514039Sstacze01@arm.com        initVirtMem.writeString(memState->getStackMin(), arg.c_str());
13614039Sstacze01@arm.com        argPointers.push_back(memState->getStackMin());
13714039Sstacze01@arm.com        if (DTRACE(Stack)) {
13814039Sstacze01@arm.com            string wrote;
13914039Sstacze01@arm.com            initVirtMem.readString(wrote, argPointers.back());
14014039Sstacze01@arm.com            DPRINTFN("Wrote arg \"%s\" to address %p\n",
14114039Sstacze01@arm.com                    wrote, (void*)memState->getStackMin());
14214039Sstacze01@arm.com        }
14314039Sstacze01@arm.com    }
14414039Sstacze01@arm.com    argPointers.push_back(0);
14514039Sstacze01@arm.com
14614039Sstacze01@arm.com    // Copy envp to stack
14714039Sstacze01@arm.com    vector<Addr> envPointers;
14814039Sstacze01@arm.com    for (const string& env: envp) {
14914039Sstacze01@arm.com        memState->setStackMin(memState->getStackMin() - (env.size() + 1));
15014039Sstacze01@arm.com        initVirtMem.writeString(memState->getStackMin(), env.c_str());
15114039Sstacze01@arm.com        envPointers.push_back(memState->getStackMin());
15214039Sstacze01@arm.com        DPRINTF(Stack, "Wrote env \"%s\" to address %p\n",
15314039Sstacze01@arm.com                env, (void*)memState->getStackMin());
15414039Sstacze01@arm.com    }
15514039Sstacze01@arm.com    envPointers.push_back(0);
15614039Sstacze01@arm.com
15714039Sstacze01@arm.com    // Align stack
15814039Sstacze01@arm.com    memState->setStackMin(memState->getStackMin() & -sizeof(Addr));
15914039Sstacze01@arm.com
16014039Sstacze01@arm.com    // Calculate bottom of stack
16114039Sstacze01@arm.com    memState->setStackMin(memState->getStackMin() -
16214039Sstacze01@arm.com            ((1 + argv.size()) * sizeof(Addr) +
16314039Sstacze01@arm.com             (1 + envp.size()) * sizeof(Addr) +
16414039Sstacze01@arm.com             sizeof(Addr) + 2 * sizeof(IntType) * auxv.size()));
16514039Sstacze01@arm.com    memState->setStackMin(memState->getStackMin() & -2*sizeof(Addr));
16614039Sstacze01@arm.com    Addr sp = memState->getStackMin();
16714039Sstacze01@arm.com    const auto pushOntoStack =
16814039Sstacze01@arm.com        [this, &sp](const uint8_t* data, const size_t size) {
16914039Sstacze01@arm.com            initVirtMem.writeBlob(sp, data, size);
17014039Sstacze01@arm.com            sp += size;
17114039Sstacze01@arm.com        };
17214039Sstacze01@arm.com
17314039Sstacze01@arm.com    // Push argc and argv pointers onto stack
17414039Sstacze01@arm.com    IntType argc = htog((IntType)argv.size());
17514039Sstacze01@arm.com    DPRINTF(Stack, "Wrote argc %d to address %p\n",
17614039Sstacze01@arm.com            argv.size(), (void*)sp);
17714039Sstacze01@arm.com    pushOntoStack((uint8_t*)&argc, sizeof(IntType));
17814039Sstacze01@arm.com    for (const Addr& argPointer: argPointers) {
17914039Sstacze01@arm.com        DPRINTF(Stack, "Wrote argv pointer %p to address %p\n",
18014039Sstacze01@arm.com                (void*)argPointer, (void*)sp);
18114039Sstacze01@arm.com        pushOntoStack((uint8_t*)&argPointer, sizeof(Addr));
18214039Sstacze01@arm.com    }
18314039Sstacze01@arm.com
18414039Sstacze01@arm.com    // Push env pointers onto stack
18514039Sstacze01@arm.com    for (const Addr& envPointer: envPointers) {
18614039Sstacze01@arm.com        DPRINTF(Stack, "Wrote envp pointer %p to address %p\n",
18714039Sstacze01@arm.com                (void*)envPointer, (void*)sp);
18814039Sstacze01@arm.com        pushOntoStack((uint8_t*)&envPointer, sizeof(Addr));
18914039Sstacze01@arm.com    }
19014039Sstacze01@arm.com
19114039Sstacze01@arm.com    // Push aux vector onto stack
19214039Sstacze01@arm.com    std::map<IntType, string> aux_keys = {
19314039Sstacze01@arm.com        {M5_AT_ENTRY, "M5_AT_ENTRY"},
19414039Sstacze01@arm.com        {M5_AT_PHNUM, "M5_AT_PHNUM"},
19514039Sstacze01@arm.com        {M5_AT_PHENT, "M5_AT_PHENT"},
19614039Sstacze01@arm.com        {M5_AT_PHDR, "M5_AT_PHDR"},
19714039Sstacze01@arm.com        {M5_AT_PAGESZ, "M5_AT_PAGESZ"},
19814039Sstacze01@arm.com        {M5_AT_SECURE, "M5_AT_SECURE"},
19914039Sstacze01@arm.com        {M5_AT_RANDOM, "M5_AT_RANDOM"},
20014039Sstacze01@arm.com        {M5_AT_NULL, "M5_AT_NULL"}
20114039Sstacze01@arm.com    };
20214039Sstacze01@arm.com    for (const AuxVector<IntType>& aux: auxv) {
20314039Sstacze01@arm.com        DPRINTF(Stack, "Wrote aux key %s to address %p\n",
20414039Sstacze01@arm.com                aux_keys[aux.a_type], (void*)sp);
20514039Sstacze01@arm.com        pushOntoStack((uint8_t*)&aux.a_type, sizeof(IntType));
20614039Sstacze01@arm.com        DPRINTF(Stack, "Wrote aux value %x to address %p\n",
20714039Sstacze01@arm.com                aux.a_val, (void*)sp);
20814039Sstacze01@arm.com        pushOntoStack((uint8_t*)&aux.a_val, sizeof(IntType));
20914039Sstacze01@arm.com    }
21014039Sstacze01@arm.com
21114039Sstacze01@arm.com    ThreadContext *tc = system->getThreadContext(contextIds[0]);
21214039Sstacze01@arm.com    tc->setIntReg(StackPointerReg, memState->getStackMin());
21314039Sstacze01@arm.com    tc->pcState(getStartPC());
21414039Sstacze01@arm.com
21514039Sstacze01@arm.com    memState->setStackMin(roundDown(memState->getStackMin(), pageSize));
21614039Sstacze01@arm.com}
21714039Sstacze01@arm.com
21814039Sstacze01@arm.comRiscvISA::IntReg
21914100Sgiacomo.travaglini@arm.comRiscvProcess::getSyscallArg(ThreadContext *tc, int &i)
22014039Sstacze01@arm.com{
22114100Sgiacomo.travaglini@arm.com    // If a larger index is requested than there are syscall argument
22214100Sgiacomo.travaglini@arm.com    // registers, return 0
22314100Sgiacomo.travaglini@arm.com    RiscvISA::IntReg retval = 0;
22414100Sgiacomo.travaglini@arm.com    if (i < SyscallArgumentRegs.size())
22514100Sgiacomo.travaglini@arm.com        retval = tc->readIntReg(SyscallArgumentRegs[i]);
22614039Sstacze01@arm.com    i++;
22714039Sstacze01@arm.com    return retval;
22814039Sstacze01@arm.com}
22914039Sstacze01@arm.com
23014039Sstacze01@arm.comvoid
23114039Sstacze01@arm.comRiscvProcess::setSyscallArg(ThreadContext *tc, int i, RiscvISA::IntReg val)
23214039Sstacze01@arm.com{
23314039Sstacze01@arm.com    tc->setIntReg(SyscallArgumentRegs[i], val);
23414039Sstacze01@arm.com}
23514098Smichiel.vantol@arm.com
23614098Smichiel.vantol@arm.comvoid
23714098Smichiel.vantol@arm.comRiscvProcess::setSyscallReturn(ThreadContext *tc, SyscallReturn sysret)
23814098Smichiel.vantol@arm.com{
23914098Smichiel.vantol@arm.com    if (sysret.successful()) {
24014098Smichiel.vantol@arm.com        // no error
24114098Smichiel.vantol@arm.com        tc->setIntReg(SyscallPseudoReturnReg, sysret.returnValue());
24214098Smichiel.vantol@arm.com    } else {
24314098Smichiel.vantol@arm.com        // got an error, return details
24414098Smichiel.vantol@arm.com        tc->setIntReg(SyscallPseudoReturnReg, sysret.errnoValue());
24514098Smichiel.vantol@arm.com    }
24614098Smichiel.vantol@arm.com}
24714098Smichiel.vantol@arm.com