process.cc revision 12431
12600SN/A/*
22600SN/A * Copyright (c) 2004-2005 The Regents of The University of Michigan
32600SN/A * Copyright (c) 2016 The University of Virginia
42600SN/A * All rights reserved.
52600SN/A *
62600SN/A * Redistribution and use in source and binary forms, with or without
72600SN/A * modification, are permitted provided that the following conditions are
82600SN/A * met: redistributions of source code must retain the above copyright
92600SN/A * notice, this list of conditions and the following disclaimer;
102600SN/A * redistributions in binary form must reproduce the above copyright
112600SN/A * notice, this list of conditions and the following disclaimer in the
122600SN/A * documentation and/or other materials provided with the distribution;
132600SN/A * neither the name of the copyright holders nor the names of its
142600SN/A * contributors may be used to endorse or promote products derived from
152600SN/A * this software without specific prior written permission.
162600SN/A *
172600SN/A * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
182600SN/A * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
192600SN/A * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
202600SN/A * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
212600SN/A * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
222600SN/A * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
232600SN/A * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
242600SN/A * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
252600SN/A * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
262600SN/A * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
272665Ssaidi@eecs.umich.edu * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
282665Ssaidi@eecs.umich.edu *
292600SN/A * Authors: Gabe Black
302600SN/A *          Ali Saidi
312600SN/A *          Korey Sewell
322600SN/A *          Alec Roelke
332600SN/A */
342600SN/A#include "arch/riscv/process.hh"
352600SN/A
362600SN/A#include <algorithm>
372600SN/A#include <cstddef>
382600SN/A#include <iostream>
392600SN/A#include <iterator>
402600SN/A#include <map>
412600SN/A#include <string>
422600SN/A#include <vector>
432600SN/A
442600SN/A#include "arch/riscv/isa_traits.hh"
452600SN/A#include "base/loader/elf_object.hh"
462600SN/A#include "base/loader/object_file.hh"
472600SN/A#include "base/logging.hh"
482600SN/A#include "base/random.hh"
492600SN/A#include "cpu/thread_context.hh"
502600SN/A#include "debug/Stack.hh"
512600SN/A#include "mem/page_table.hh"
522600SN/A#include "params/Process.hh"
532600SN/A#include "sim/aux_vector.hh"
542600SN/A#include "sim/process.hh"
552600SN/A#include "sim/process_impl.hh"
562600SN/A#include "sim/syscall_return.hh"
572600SN/A#include "sim/system.hh"
582600SN/A
592600SN/Ausing namespace std;
602600SN/Ausing namespace RiscvISA;
612600SN/A
622600SN/ARiscvProcess::RiscvProcess(ProcessParams *params, ObjectFile *objFile) :
632600SN/A        Process(params, new FuncPageTable(params->name, params->pid), objFile)
642600SN/A{
652600SN/A    fatal_if(!params->useArchPT, "Arch page tables not implemented.");
662600SN/A    const Addr stack_base = 0x7FFFFFFFFFFFFFFFL;
672600SN/A    const Addr max_stack_size = 8 * 1024 * 1024;
682600SN/A    const Addr next_thread_stack_base = stack_base - max_stack_size;
692600SN/A    const Addr brk_point = roundUp(objFile->bssBase() + objFile->bssSize(),
702600SN/A            PageBytes);
712600SN/A    const Addr mmap_end = 0x4000000000000000L;
722600SN/A    memState = make_shared<MemState>(brk_point, stack_base, max_stack_size,
732600SN/A            next_thread_stack_base, mmap_end);
742600SN/A}
752600SN/A
762600SN/Avoid
772600SN/ARiscvProcess::initState()
782600SN/A{
792600SN/A    Process::initState();
802600SN/A
812600SN/A    argsInit<uint64_t>(PageBytes);
822600SN/A}
832600SN/A
842600SN/Atemplate<class IntType> void
852600SN/ARiscvProcess::argsInit(int pageSize)
862600SN/A{
872600SN/A    const int RandomBytes = 16;
882600SN/A
892600SN/A    updateBias();
902600SN/A    objFile->loadSections(initVirtMem);
912600SN/A    ElfObject* elfObject = dynamic_cast<ElfObject*>(objFile);
922600SN/A    memState->setStackMin(memState->getStackBase());
932600SN/A
942600SN/A    // Determine stack size and populate auxv
952600SN/A    Addr stack_top = memState->getStackMin();
962600SN/A    stack_top -= RandomBytes;
972600SN/A    for (const string& arg: argv)
982600SN/A        stack_top -= arg.size() + 1;
992600SN/A    for (const string& env: envp)
1002600SN/A        stack_top -= env.size() + 1;
1012600SN/A    stack_top &= -sizeof(Addr);
1022600SN/A
1032600SN/A    vector<AuxVector<IntType>> auxv;
1042600SN/A    if (elfObject != nullptr) {
1052600SN/A        auxv.push_back({M5_AT_ENTRY, objFile->entryPoint()});
1062600SN/A        auxv.push_back({M5_AT_PHNUM, elfObject->programHeaderCount()});
1072600SN/A        auxv.push_back({M5_AT_PHENT, elfObject->programHeaderSize()});
1082600SN/A        auxv.push_back({M5_AT_PHDR, elfObject->programHeaderTable()});
1092600SN/A        auxv.push_back({M5_AT_PAGESZ, PageBytes});
1102600SN/A        auxv.push_back({M5_AT_SECURE, 0});
1112600SN/A        auxv.push_back({M5_AT_RANDOM, stack_top});
1122600SN/A        auxv.push_back({M5_AT_NULL, 0});
1132600SN/A    }
1142600SN/A    stack_top -= (1 + argv.size()) * sizeof(Addr) +
1152600SN/A                   (1 + envp.size()) * sizeof(Addr) +
1162600SN/A                   sizeof(Addr) + 2 * sizeof(IntType) * auxv.size();
1172600SN/A    stack_top &= -2*sizeof(Addr);
1182600SN/A    memState->setStackSize(memState->getStackBase() - stack_top);
1192600SN/A    allocateMem(roundDown(stack_top, pageSize),
1202600SN/A            roundUp(memState->getStackSize(), pageSize));
1212600SN/A
1222600SN/A    // Copy random bytes (for AT_RANDOM) to stack
1232600SN/A    memState->setStackMin(memState->getStackMin() - RandomBytes);
1242600SN/A    uint8_t at_random[RandomBytes];
1252600SN/A    generate(begin(at_random), end(at_random),
1262600SN/A             [&]{ return random_mt.random(0, 0xFF); });
1272600SN/A    initVirtMem.writeBlob(memState->getStackMin(), at_random, RandomBytes);
1282600SN/A
1292600SN/A    // Copy argv to stack
1302600SN/A    vector<Addr> argPointers;
1312600SN/A    for (const string& arg: argv) {
1322600SN/A        memState->setStackMin(memState->getStackMin() - (arg.size() + 1));
1332600SN/A        initVirtMem.writeString(memState->getStackMin(), arg.c_str());
1342600SN/A        argPointers.push_back(memState->getStackMin());
1352600SN/A        if (DTRACE(Stack)) {
1362600SN/A            string wrote;
1372600SN/A            initVirtMem.readString(wrote, argPointers.back());
1382600SN/A            DPRINTFN("Wrote arg \"%s\" to address %p\n",
1392600SN/A                    wrote, (void*)memState->getStackMin());
1402600SN/A        }
1412600SN/A    }
1422600SN/A    argPointers.push_back(0);
1432600SN/A
1442600SN/A    // Copy envp to stack
1452600SN/A    vector<Addr> envPointers;
1462600SN/A    for (const string& env: envp) {
1472600SN/A        memState->setStackMin(memState->getStackMin() - (env.size() + 1));
1482600SN/A        initVirtMem.writeString(memState->getStackMin(), env.c_str());
1492600SN/A        envPointers.push_back(memState->getStackMin());
1502600SN/A        DPRINTF(Stack, "Wrote env \"%s\" to address %p\n",
1512600SN/A                env, (void*)memState->getStackMin());
1522600SN/A    }
1532600SN/A    envPointers.push_back(0);
1542600SN/A
1552600SN/A    // Align stack
1562600SN/A    memState->setStackMin(memState->getStackMin() & -sizeof(Addr));
1572600SN/A
1582600SN/A    // Calculate bottom of stack
1592600SN/A    memState->setStackMin(memState->getStackMin() -
1602600SN/A            ((1 + argv.size()) * sizeof(Addr) +
1612600SN/A             (1 + envp.size()) * sizeof(Addr) +
1622600SN/A             sizeof(Addr) + 2 * sizeof(IntType) * auxv.size()));
1632600SN/A    memState->setStackMin(memState->getStackMin() & -2*sizeof(Addr));
1642600SN/A    Addr sp = memState->getStackMin();
1652600SN/A    const auto pushOntoStack =
1662600SN/A        [this, &sp](const uint8_t* data, const size_t size) {
1672600SN/A            initVirtMem.writeBlob(sp, data, size);
1682600SN/A            sp += size;
1692600SN/A        };
1702600SN/A
1712600SN/A    // Push argc and argv pointers onto stack
1722600SN/A    IntType argc = htog((IntType)argv.size());
1732600SN/A    DPRINTF(Stack, "Wrote argc %d to address %p\n",
1742600SN/A            argv.size(), (void*)sp);
1752600SN/A    pushOntoStack((uint8_t*)&argc, sizeof(IntType));
1762600SN/A    for (const Addr& argPointer: argPointers) {
1772600SN/A        DPRINTF(Stack, "Wrote argv pointer %p to address %p\n",
1782600SN/A                (void*)argPointer, (void*)sp);
1792600SN/A        pushOntoStack((uint8_t*)&argPointer, sizeof(Addr));
1802600SN/A    }
1812600SN/A
1822600SN/A    // Push env pointers onto stack
1832600SN/A    for (const Addr& envPointer: envPointers) {
1842600SN/A        DPRINTF(Stack, "Wrote envp pointer %p to address %p\n",
1852600SN/A                (void*)envPointer, (void*)sp);
1862600SN/A        pushOntoStack((uint8_t*)&envPointer, sizeof(Addr));
1872600SN/A    }
1882600SN/A
1892600SN/A    // Push aux vector onto stack
1902600SN/A    std::map<IntType, string> aux_keys = {
1912600SN/A        {M5_AT_ENTRY, "M5_AT_ENTRY"},
1922600SN/A        {M5_AT_PHNUM, "M5_AT_PHNUM"},
1932600SN/A        {M5_AT_PHENT, "M5_AT_PHENT"},
1942600SN/A        {M5_AT_PHDR, "M5_AT_PHDR"},
1952600SN/A        {M5_AT_PAGESZ, "M5_AT_PAGESZ"},
1962600SN/A        {M5_AT_SECURE, "M5_AT_SECURE"},
1972600SN/A        {M5_AT_RANDOM, "M5_AT_RANDOM"},
1982600SN/A        {M5_AT_NULL, "M5_AT_NULL"}
1992600SN/A    };
2002600SN/A    for (const AuxVector<IntType>& aux: auxv) {
2012600SN/A        DPRINTF(Stack, "Wrote aux key %s to address %p\n",
2022600SN/A                aux_keys[aux.a_type], (void*)sp);
2032600SN/A        pushOntoStack((uint8_t*)&aux.a_type, sizeof(IntType));
2042600SN/A        DPRINTF(Stack, "Wrote aux value %x to address %p\n",
2052600SN/A                aux.a_val, (void*)sp);
2062600SN/A        pushOntoStack((uint8_t*)&aux.a_val, sizeof(IntType));
2072600SN/A    }
2082600SN/A
2092600SN/A    ThreadContext *tc = system->getThreadContext(contextIds[0]);
2102600SN/A    tc->setIntReg(StackPointerReg, memState->getStackMin());
2112600SN/A    tc->pcState(getStartPC());
2122600SN/A
2132600SN/A    memState->setStackMin(roundDown(memState->getStackMin(), pageSize));
2142600SN/A}
2152600SN/A
2162600SN/ARiscvISA::IntReg
2172600SN/ARiscvProcess::getSyscallArg(ThreadContext *tc, int &i)
2182600SN/A{
2192600SN/A    // If a larger index is requested than there are syscall argument
2202600SN/A    // registers, return 0
2212600SN/A    RiscvISA::IntReg retval = 0;
2222600SN/A    if (i < SyscallArgumentRegs.size())
2232600SN/A        retval = tc->readIntReg(SyscallArgumentRegs[i]);
2242600SN/A    i++;
2252600SN/A    return retval;
2262600SN/A}
2272600SN/A
2282600SN/Avoid
2292600SN/ARiscvProcess::setSyscallArg(ThreadContext *tc, int i, RiscvISA::IntReg val)
2302600SN/A{
2312600SN/A    tc->setIntReg(SyscallArgumentRegs[i], val);
2322600SN/A}
2332600SN/A
2342600SN/Avoid
2352600SN/ARiscvProcess::setSyscallReturn(ThreadContext *tc, SyscallReturn sysret)
2362600SN/A{
2372600SN/A    if (sysret.successful()) {
2382600SN/A        // no error
2392600SN/A        tc->setIntReg(SyscallPseudoReturnReg, sysret.returnValue());
2402600SN/A    } else {
2412600SN/A        // got an error, return details
2422600SN/A        tc->setIntReg(SyscallPseudoReturnReg, sysret.errnoValue());
2432600SN/A    }
2442600SN/A}
2452600SN/A