2 * Copyright (c) 2004-2005 The Regents of The University of Michigan
3 * Copyright (c) 2016 The University of Virginia
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions are
8 * met: redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer;
10 * redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution;
13 * neither the name of the copyright holders nor the names of its
14 * contributors may be used to endorse or promote products derived from
15 * this software without specific prior written permission.
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
20 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
21 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
22 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
23 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34 #include "arch/riscv/process.hh"
44 #include "arch/riscv/isa_traits.hh"
45 #include "base/loader/elf_object.hh"
46 #include "base/loader/object_file.hh"
47 #include "base/logging.hh"
48 #include "base/random.hh"
49 #include "cpu/thread_context.hh"
50 #include "debug/Stack.hh"
51 #include "mem/page_table.hh"
52 #include "params/Process.hh"
53 #include "sim/aux_vector.hh"
54 #include "sim/process.hh"
55 #include "sim/process_impl.hh"
56 #include "sim/syscall_return.hh"
57 #include "sim/system.hh"
60 using namespace RiscvISA
;
62 RiscvProcess::RiscvProcess(ProcessParams
* params
,
63 ObjectFile
*objFile
) : Process(params
, objFile
)
65 const Addr stack_base
= 0x7FFFFFFFFFFFFFFFL
;
66 const Addr max_stack_size
= 8 * 1024 * 1024;
67 const Addr next_thread_stack_base
= stack_base
- max_stack_size
;
68 const Addr brk_point
= roundUp(objFile
->bssBase() + objFile
->bssSize(),
70 const Addr mmap_end
= 0x4000000000000000L
;
71 memState
= make_shared
<MemState
>(brk_point
, stack_base
, max_stack_size
,
72 next_thread_stack_base
, mmap_end
);
76 RiscvProcess::initState()
80 argsInit
<uint64_t>(PageBytes
);
83 template<class IntType
> void
84 RiscvProcess::argsInit(int pageSize
)
86 const int RandomBytes
= 16;
89 objFile
->loadSections(initVirtMem
);
90 ElfObject
* elfObject
= dynamic_cast<ElfObject
*>(objFile
);
91 memState
->setStackMin(memState
->getStackBase());
93 // Determine stack size and populate auxv
94 Addr stack_top
= memState
->getStackMin();
95 stack_top
-= RandomBytes
;
96 for (const string
& arg
: argv
)
97 stack_top
-= arg
.size() + 1;
98 for (const string
& env
: envp
)
99 stack_top
-= env
.size() + 1;
100 stack_top
&= -sizeof(Addr
);
102 vector
<AuxVector
<IntType
>> auxv
;
103 if (elfObject
!= nullptr) {
104 auxv
.push_back({M5_AT_ENTRY
, objFile
->entryPoint()});
105 auxv
.push_back({M5_AT_PHNUM
, elfObject
->programHeaderCount()});
106 auxv
.push_back({M5_AT_PHENT
, elfObject
->programHeaderSize()});
107 auxv
.push_back({M5_AT_PHDR
, elfObject
->programHeaderTable()});
108 auxv
.push_back({M5_AT_PAGESZ
, PageBytes
});
109 auxv
.push_back({M5_AT_SECURE
, 0});
110 auxv
.push_back({M5_AT_RANDOM
, stack_top
});
111 auxv
.push_back({M5_AT_NULL
, 0});
113 stack_top
-= (1 + argv
.size()) * sizeof(Addr
) +
114 (1 + envp
.size()) * sizeof(Addr
) +
115 sizeof(Addr
) + 2 * sizeof(IntType
) * auxv
.size();
116 stack_top
&= -2*sizeof(Addr
);
117 memState
->setStackSize(memState
->getStackBase() - stack_top
);
118 allocateMem(roundDown(stack_top
, pageSize
),
119 roundUp(memState
->getStackSize(), pageSize
));
121 // Copy random bytes (for AT_RANDOM) to stack
122 memState
->setStackMin(memState
->getStackMin() - RandomBytes
);
123 uint8_t at_random
[RandomBytes
];
124 generate(begin(at_random
), end(at_random
),
125 [&]{ return random_mt
.random(0, 0xFF); });
126 initVirtMem
.writeBlob(memState
->getStackMin(), at_random
, RandomBytes
);
128 // Copy argv to stack
129 vector
<Addr
> argPointers
;
130 for (const string
& arg
: argv
) {
131 memState
->setStackMin(memState
->getStackMin() - (arg
.size() + 1));
132 initVirtMem
.writeString(memState
->getStackMin(), arg
.c_str());
133 argPointers
.push_back(memState
->getStackMin());
136 initVirtMem
.readString(wrote
, argPointers
.back());
137 DPRINTFN("Wrote arg \"%s\" to address %p\n",
138 wrote
, (void*)memState
->getStackMin());
141 argPointers
.push_back(0);
143 // Copy envp to stack
144 vector
<Addr
> envPointers
;
145 for (const string
& env
: envp
) {
146 memState
->setStackMin(memState
->getStackMin() - (env
.size() + 1));
147 initVirtMem
.writeString(memState
->getStackMin(), env
.c_str());
148 envPointers
.push_back(memState
->getStackMin());
149 DPRINTF(Stack
, "Wrote env \"%s\" to address %p\n",
150 env
, (void*)memState
->getStackMin());
152 envPointers
.push_back(0);
155 memState
->setStackMin(memState
->getStackMin() & -sizeof(Addr
));
157 // Calculate bottom of stack
158 memState
->setStackMin(memState
->getStackMin() -
159 ((1 + argv
.size()) * sizeof(Addr
) +
160 (1 + envp
.size()) * sizeof(Addr
) +
161 sizeof(Addr
) + 2 * sizeof(IntType
) * auxv
.size()));
162 memState
->setStackMin(memState
->getStackMin() & -2*sizeof(Addr
));
163 Addr sp
= memState
->getStackMin();
164 const auto pushOntoStack
=
165 [this, &sp
](const uint8_t* data
, const size_t size
) {
166 initVirtMem
.writeBlob(sp
, data
, size
);
170 // Push argc and argv pointers onto stack
171 IntType argc
= htog((IntType
)argv
.size());
172 DPRINTF(Stack
, "Wrote argc %d to address %p\n",
173 argv
.size(), (void*)sp
);
174 pushOntoStack((uint8_t*)&argc
, sizeof(IntType
));
175 for (const Addr
& argPointer
: argPointers
) {
176 DPRINTF(Stack
, "Wrote argv pointer %p to address %p\n",
177 (void*)argPointer
, (void*)sp
);
178 pushOntoStack((uint8_t*)&argPointer
, sizeof(Addr
));
181 // Push env pointers onto stack
182 for (const Addr
& envPointer
: envPointers
) {
183 DPRINTF(Stack
, "Wrote envp pointer %p to address %p\n",
184 (void*)envPointer
, (void*)sp
);
185 pushOntoStack((uint8_t*)&envPointer
, sizeof(Addr
));
188 // Push aux vector onto stack
189 std::map
<IntType
, string
> aux_keys
= {
190 {M5_AT_ENTRY
, "M5_AT_ENTRY"},
191 {M5_AT_PHNUM
, "M5_AT_PHNUM"},
192 {M5_AT_PHENT
, "M5_AT_PHENT"},
193 {M5_AT_PHDR
, "M5_AT_PHDR"},
194 {M5_AT_PAGESZ
, "M5_AT_PAGESZ"},
195 {M5_AT_SECURE
, "M5_AT_SECURE"},
196 {M5_AT_RANDOM
, "M5_AT_RANDOM"},
197 {M5_AT_NULL
, "M5_AT_NULL"}
199 for (const AuxVector
<IntType
>& aux
: auxv
) {
200 DPRINTF(Stack
, "Wrote aux key %s to address %p\n",
201 aux_keys
[aux
.a_type
], (void*)sp
);
202 pushOntoStack((uint8_t*)&aux
.a_type
, sizeof(IntType
));
203 DPRINTF(Stack
, "Wrote aux value %x to address %p\n",
204 aux
.a_val
, (void*)sp
);
205 pushOntoStack((uint8_t*)&aux
.a_val
, sizeof(IntType
));
208 ThreadContext
*tc
= system
->getThreadContext(contextIds
[0]);
209 tc
->setIntReg(StackPointerReg
, memState
->getStackMin());
210 tc
->pcState(getStartPC());
212 memState
->setStackMin(roundDown(memState
->getStackMin(), pageSize
));
216 RiscvProcess::getSyscallArg(ThreadContext
*tc
, int &i
)
218 // If a larger index is requested than there are syscall argument
219 // registers, return 0
220 RiscvISA::IntReg retval
= 0;
221 if (i
< SyscallArgumentRegs
.size())
222 retval
= tc
->readIntReg(SyscallArgumentRegs
[i
]);
228 RiscvProcess::setSyscallArg(ThreadContext
*tc
, int i
, RiscvISA::IntReg val
)
230 tc
->setIntReg(SyscallArgumentRegs
[i
], val
);
234 RiscvProcess::setSyscallReturn(ThreadContext
*tc
, SyscallReturn sysret
)
236 if (sysret
.successful()) {
238 tc
->setIntReg(SyscallPseudoReturnReg
, sysret
.returnValue());
240 // got an error, return details
241 tc
->setIntReg(SyscallPseudoReturnReg
, sysret
.errnoValue());