process.cc revision 8601
19616Sandreas.hansson@arm.com/*
29616Sandreas.hansson@arm.com * Copyright (c) 2007-2008 The Florida State University
39616Sandreas.hansson@arm.com * Copyright (c) 2009 The University of Edinburgh
49616Sandreas.hansson@arm.com * All rights reserved.
59616Sandreas.hansson@arm.com *
69616Sandreas.hansson@arm.com * Redistribution and use in source and binary forms, with or without
79616Sandreas.hansson@arm.com * modification, are permitted provided that the following conditions are
89616Sandreas.hansson@arm.com * met: redistributions of source code must retain the above copyright
99616Sandreas.hansson@arm.com * notice, this list of conditions and the following disclaimer;
109616Sandreas.hansson@arm.com * redistributions in binary form must reproduce the above copyright
119616Sandreas.hansson@arm.com * notice, this list of conditions and the following disclaimer in the
129616Sandreas.hansson@arm.com * documentation and/or other materials provided with the distribution;
139616Sandreas.hansson@arm.com * neither the name of the copyright holders nor the names of its
149616Sandreas.hansson@arm.com * contributors may be used to endorse or promote products derived from
159616Sandreas.hansson@arm.com * this software without specific prior written permission.
169616Sandreas.hansson@arm.com *
179616Sandreas.hansson@arm.com * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
189616Sandreas.hansson@arm.com * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
199616Sandreas.hansson@arm.com * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
209616Sandreas.hansson@arm.com * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
219616Sandreas.hansson@arm.com * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
229616Sandreas.hansson@arm.com * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
239616Sandreas.hansson@arm.com * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
249616Sandreas.hansson@arm.com * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
259616Sandreas.hansson@arm.com * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
269616Sandreas.hansson@arm.com * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
279616Sandreas.hansson@arm.com * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
289616Sandreas.hansson@arm.com *
299616Sandreas.hansson@arm.com * Authors: Stephen Hines
309616Sandreas.hansson@arm.com *          Timothy M. Jones
319616Sandreas.hansson@arm.com */
329616Sandreas.hansson@arm.com
339616Sandreas.hansson@arm.com#include "arch/power/isa_traits.hh"
349616Sandreas.hansson@arm.com#include "arch/power/process.hh"
359616Sandreas.hansson@arm.com#include "arch/power/types.hh"
369616Sandreas.hansson@arm.com#include "base/loader/elf_object.hh"
379616Sandreas.hansson@arm.com#include "base/loader/object_file.hh"
389616Sandreas.hansson@arm.com#include "base/misc.hh"
399616Sandreas.hansson@arm.com#include "cpu/thread_context.hh"
409616Sandreas.hansson@arm.com#include "debug/Stack.hh"
419616Sandreas.hansson@arm.com#include "mem/page_table.hh"
429616Sandreas.hansson@arm.com#include "mem/translating_port.hh"
439616Sandreas.hansson@arm.com#include "sim/process_impl.hh"
449616Sandreas.hansson@arm.com#include "sim/system.hh"
459616Sandreas.hansson@arm.com
469616Sandreas.hansson@arm.comusing namespace std;
479616Sandreas.hansson@arm.comusing namespace PowerISA;
489616Sandreas.hansson@arm.com
499616Sandreas.hansson@arm.comPowerLiveProcess::PowerLiveProcess(LiveProcessParams *params,
509616Sandreas.hansson@arm.com        ObjectFile *objFile)
519616Sandreas.hansson@arm.com    : LiveProcess(params, objFile)
529616Sandreas.hansson@arm.com{
539616Sandreas.hansson@arm.com    stack_base = 0xbf000000L;
549616Sandreas.hansson@arm.com
559616Sandreas.hansson@arm.com    // Set pointer for next thread stack.  Reserve 8M for main stack.
569616Sandreas.hansson@arm.com    next_thread_stack_base = stack_base - (8 * 1024 * 1024);
579616Sandreas.hansson@arm.com
589616Sandreas.hansson@arm.com    // Set up break point (Top of Heap)
599616Sandreas.hansson@arm.com    brk_point = objFile->dataBase() + objFile->dataSize() + objFile->bssSize();
609616Sandreas.hansson@arm.com    brk_point = roundUp(brk_point, VMPageSize);
619616Sandreas.hansson@arm.com
629616Sandreas.hansson@arm.com    // Set up region for mmaps. For now, start at bottom of kuseg space.
639616Sandreas.hansson@arm.com    mmap_start = mmap_end = 0x70000000L;
649616Sandreas.hansson@arm.com}
659616Sandreas.hansson@arm.com
669616Sandreas.hansson@arm.comvoid
679616Sandreas.hansson@arm.comPowerLiveProcess::initState()
689616Sandreas.hansson@arm.com{
699616Sandreas.hansson@arm.com    Process::initState();
709616Sandreas.hansson@arm.com
719616Sandreas.hansson@arm.com    argsInit(MachineBytes, VMPageSize);
729616Sandreas.hansson@arm.com}
739616Sandreas.hansson@arm.com
749616Sandreas.hansson@arm.comvoid
759616Sandreas.hansson@arm.comPowerLiveProcess::argsInit(int intSize, int pageSize)
769616Sandreas.hansson@arm.com{
779616Sandreas.hansson@arm.com    typedef AuxVector<uint32_t> auxv_t;
789616Sandreas.hansson@arm.com    std::vector<auxv_t> auxv;
799616Sandreas.hansson@arm.com
809616Sandreas.hansson@arm.com    string filename;
819616Sandreas.hansson@arm.com    if (argv.size() < 1)
829616Sandreas.hansson@arm.com        filename = "";
839616Sandreas.hansson@arm.com    else
849616Sandreas.hansson@arm.com        filename = argv[0];
859616Sandreas.hansson@arm.com
869616Sandreas.hansson@arm.com    //We want 16 byte alignment
879616Sandreas.hansson@arm.com    uint64_t align = 16;
889706Sandreas.hansson@arm.com
899706Sandreas.hansson@arm.com    // load object file into target memory
909706Sandreas.hansson@arm.com    objFile->loadSections(initVirtMem);
919706Sandreas.hansson@arm.com
929706Sandreas.hansson@arm.com    //Setup the auxilliary vectors. These will already have endian conversion.
939706Sandreas.hansson@arm.com    //Auxilliary vectors are loaded only for elf formatted executables.
949706Sandreas.hansson@arm.com    ElfObject * elfObject = dynamic_cast<ElfObject *>(objFile);
959706Sandreas.hansson@arm.com    if (elfObject) {
969706Sandreas.hansson@arm.com        uint32_t features = 0;
979706Sandreas.hansson@arm.com
989706Sandreas.hansson@arm.com        //Bits which describe the system hardware capabilities
999706Sandreas.hansson@arm.com        //XXX Figure out what these should be
1009706Sandreas.hansson@arm.com        auxv.push_back(auxv_t(M5_AT_HWCAP, features));
1019706Sandreas.hansson@arm.com        //The system page size
1029706Sandreas.hansson@arm.com        auxv.push_back(auxv_t(M5_AT_PAGESZ, PowerISA::VMPageSize));
1039706Sandreas.hansson@arm.com        //Frequency at which times() increments
1049706Sandreas.hansson@arm.com        auxv.push_back(auxv_t(M5_AT_CLKTCK, 0x64));
1059616Sandreas.hansson@arm.com        // For statically linked executables, this is the virtual address of the
1069616Sandreas.hansson@arm.com        // program header tables if they appear in the executable image
1079616Sandreas.hansson@arm.com        auxv.push_back(auxv_t(M5_AT_PHDR, elfObject->programHeaderTable()));
1089616Sandreas.hansson@arm.com        // This is the size of a program header entry from the elf file.
1099616Sandreas.hansson@arm.com        auxv.push_back(auxv_t(M5_AT_PHENT, elfObject->programHeaderSize()));
1109616Sandreas.hansson@arm.com        // This is the number of program headers from the original elf file.
1119616Sandreas.hansson@arm.com        auxv.push_back(auxv_t(M5_AT_PHNUM, elfObject->programHeaderCount()));
1129616Sandreas.hansson@arm.com        //This is the address of the elf "interpreter", It should be set
1139616Sandreas.hansson@arm.com        //to 0 for regular executables. It should be something else
1149616Sandreas.hansson@arm.com        //(not sure what) for dynamic libraries.
1159616Sandreas.hansson@arm.com        auxv.push_back(auxv_t(M5_AT_BASE, 0));
1169616Sandreas.hansson@arm.com
1179616Sandreas.hansson@arm.com        //XXX Figure out what this should be.
1189616Sandreas.hansson@arm.com        auxv.push_back(auxv_t(M5_AT_FLAGS, 0));
1199616Sandreas.hansson@arm.com        //The entry point to the program
1209616Sandreas.hansson@arm.com        auxv.push_back(auxv_t(M5_AT_ENTRY, objFile->entryPoint()));
1219616Sandreas.hansson@arm.com        //Different user and group IDs
1229616Sandreas.hansson@arm.com        auxv.push_back(auxv_t(M5_AT_UID, uid()));
1239616Sandreas.hansson@arm.com        auxv.push_back(auxv_t(M5_AT_EUID, euid()));
1249616Sandreas.hansson@arm.com        auxv.push_back(auxv_t(M5_AT_GID, gid()));
1259616Sandreas.hansson@arm.com        auxv.push_back(auxv_t(M5_AT_EGID, egid()));
1269616Sandreas.hansson@arm.com        //Whether to enable "secure mode" in the executable
1279616Sandreas.hansson@arm.com        auxv.push_back(auxv_t(M5_AT_SECURE, 0));
1289616Sandreas.hansson@arm.com        //The filename of the program
1299616Sandreas.hansson@arm.com        auxv.push_back(auxv_t(M5_AT_EXECFN, 0));
1309616Sandreas.hansson@arm.com        //The string "v51" with unknown meaning
1319616Sandreas.hansson@arm.com        auxv.push_back(auxv_t(M5_AT_PLATFORM, 0));
1329616Sandreas.hansson@arm.com    }
1339616Sandreas.hansson@arm.com
1349616Sandreas.hansson@arm.com    //Figure out how big the initial stack nedes to be
1359616Sandreas.hansson@arm.com
1369616Sandreas.hansson@arm.com    // A sentry NULL void pointer at the top of the stack.
1379616Sandreas.hansson@arm.com    int sentry_size = intSize;
1389616Sandreas.hansson@arm.com
1399616Sandreas.hansson@arm.com    string platform = "v51";
1409616Sandreas.hansson@arm.com    int platform_size = platform.size() + 1;
1419616Sandreas.hansson@arm.com
1429616Sandreas.hansson@arm.com    // The aux vectors are put on the stack in two groups. The first group are
1439616Sandreas.hansson@arm.com    // the vectors that are generated as the elf is loaded. The second group
1449616Sandreas.hansson@arm.com    // are the ones that were computed ahead of time and include the platform
1459616Sandreas.hansson@arm.com    // string.
1469616Sandreas.hansson@arm.com    int aux_data_size = filename.size() + 1;
1479616Sandreas.hansson@arm.com
1489616Sandreas.hansson@arm.com    int env_data_size = 0;
1499616Sandreas.hansson@arm.com    for (int i = 0; i < envp.size(); ++i) {
1509616Sandreas.hansson@arm.com        env_data_size += envp[i].size() + 1;
1519616Sandreas.hansson@arm.com    }
1529616Sandreas.hansson@arm.com    int arg_data_size = 0;
1539616Sandreas.hansson@arm.com    for (int i = 0; i < argv.size(); ++i) {
1549616Sandreas.hansson@arm.com        arg_data_size += argv[i].size() + 1;
1559616Sandreas.hansson@arm.com    }
1569616Sandreas.hansson@arm.com
1579616Sandreas.hansson@arm.com    int info_block_size =
1589616Sandreas.hansson@arm.com        sentry_size + env_data_size + arg_data_size +
1599616Sandreas.hansson@arm.com        aux_data_size + platform_size;
1609616Sandreas.hansson@arm.com
1619616Sandreas.hansson@arm.com    //Each auxilliary vector is two 4 byte words
1629616Sandreas.hansson@arm.com    int aux_array_size = intSize * 2 * (auxv.size() + 1);
1639616Sandreas.hansson@arm.com
1649616Sandreas.hansson@arm.com    int envp_array_size = intSize * (envp.size() + 1);
1659616Sandreas.hansson@arm.com    int argv_array_size = intSize * (argv.size() + 1);
1669616Sandreas.hansson@arm.com
1679616Sandreas.hansson@arm.com    int argc_size = intSize;
1689616Sandreas.hansson@arm.com
1699616Sandreas.hansson@arm.com    //Figure out the size of the contents of the actual initial frame
1709616Sandreas.hansson@arm.com    int frame_size =
1719616Sandreas.hansson@arm.com        info_block_size +
1729616Sandreas.hansson@arm.com        aux_array_size +
1739616Sandreas.hansson@arm.com        envp_array_size +
174        argv_array_size +
175        argc_size;
176
177    //There needs to be padding after the auxiliary vector data so that the
178    //very bottom of the stack is aligned properly.
179    int partial_size = frame_size;
180    int aligned_partial_size = roundUp(partial_size, align);
181    int aux_padding = aligned_partial_size - partial_size;
182
183    int space_needed = frame_size + aux_padding;
184
185    stack_min = stack_base - space_needed;
186    stack_min = roundDown(stack_min, align);
187    stack_size = stack_base - stack_min;
188
189    // map memory
190    allocateMem(roundDown(stack_min, pageSize), roundUp(stack_size, pageSize));
191
192    // map out initial stack contents
193    uint32_t sentry_base = stack_base - sentry_size;
194    uint32_t aux_data_base = sentry_base - aux_data_size;
195    uint32_t env_data_base = aux_data_base - env_data_size;
196    uint32_t arg_data_base = env_data_base - arg_data_size;
197    uint32_t platform_base = arg_data_base - platform_size;
198    uint32_t auxv_array_base = platform_base - aux_array_size - aux_padding;
199    uint32_t envp_array_base = auxv_array_base - envp_array_size;
200    uint32_t argv_array_base = envp_array_base - argv_array_size;
201    uint32_t argc_base = argv_array_base - argc_size;
202
203    DPRINTF(Stack, "The addresses of items on the initial stack:\n");
204    DPRINTF(Stack, "0x%x - aux data\n", aux_data_base);
205    DPRINTF(Stack, "0x%x - env data\n", env_data_base);
206    DPRINTF(Stack, "0x%x - arg data\n", arg_data_base);
207    DPRINTF(Stack, "0x%x - platform base\n", platform_base);
208    DPRINTF(Stack, "0x%x - auxv array\n", auxv_array_base);
209    DPRINTF(Stack, "0x%x - envp array\n", envp_array_base);
210    DPRINTF(Stack, "0x%x - argv array\n", argv_array_base);
211    DPRINTF(Stack, "0x%x - argc \n", argc_base);
212    DPRINTF(Stack, "0x%x - stack min\n", stack_min);
213
214    // write contents to stack
215
216    // figure out argc
217    uint32_t argc = argv.size();
218    uint32_t guestArgc = PowerISA::htog(argc);
219
220    //Write out the sentry void *
221    uint32_t sentry_NULL = 0;
222    initVirtMem->writeBlob(sentry_base,
223            (uint8_t*)&sentry_NULL, sentry_size);
224
225    //Fix up the aux vectors which point to other data
226    for (int i = auxv.size() - 1; i >= 0; i--) {
227        if (auxv[i].a_type == M5_AT_PLATFORM) {
228            auxv[i].a_val = platform_base;
229            initVirtMem->writeString(platform_base, platform.c_str());
230        } else if (auxv[i].a_type == M5_AT_EXECFN) {
231            auxv[i].a_val = aux_data_base;
232            initVirtMem->writeString(aux_data_base, filename.c_str());
233        }
234    }
235
236    //Copy the aux stuff
237    for (int x = 0; x < auxv.size(); x++)
238    {
239        initVirtMem->writeBlob(auxv_array_base + x * 2 * intSize,
240                (uint8_t*)&(auxv[x].a_type), intSize);
241        initVirtMem->writeBlob(auxv_array_base + (x * 2 + 1) * intSize,
242                (uint8_t*)&(auxv[x].a_val), intSize);
243    }
244    //Write out the terminating zeroed auxilliary vector
245    const uint64_t zero = 0;
246    initVirtMem->writeBlob(auxv_array_base + 2 * intSize * auxv.size(),
247            (uint8_t*)&zero, 2 * intSize);
248
249    copyStringArray(envp, envp_array_base, env_data_base, initVirtMem);
250    copyStringArray(argv, argv_array_base, arg_data_base, initVirtMem);
251
252    initVirtMem->writeBlob(argc_base, (uint8_t*)&guestArgc, intSize);
253
254    ThreadContext *tc = system->getThreadContext(contextIds[0]);
255
256    //Set the stack pointer register
257    tc->setIntReg(StackPointerReg, stack_min);
258
259    tc->pcState(objFile->entryPoint());
260
261    //Align the "stack_min" to a page boundary.
262    stack_min = roundDown(stack_min, pageSize);
263}
264
265PowerISA::IntReg
266PowerLiveProcess::getSyscallArg(ThreadContext *tc, int &i)
267{
268    assert(i < 5);
269    return tc->readIntReg(ArgumentReg0 + i++);
270}
271
272void
273PowerLiveProcess::setSyscallArg(ThreadContext *tc,
274        int i, PowerISA::IntReg val)
275{
276    assert(i < 5);
277    tc->setIntReg(ArgumentReg0 + i, val);
278}
279
280void
281PowerLiveProcess::setSyscallReturn(ThreadContext *tc,
282        SyscallReturn return_value)
283{
284    Cr cr = tc->readIntReg(INTREG_CR);
285    if (return_value.successful()) {
286        cr.cr0.so = 0;
287    } else {
288        cr.cr0.so = 1;
289    }
290    tc->setIntReg(INTREG_CR, cr);
291    tc->setIntReg(ReturnValueReg, return_value.value());
292}
293