arch-power: Update copyrights
[gem5.git] / src / arch / power / process.cc
1 /*
2 * Copyright (c) 2007-2008 The Florida State University
3 * Copyright (c) 2009 The University of Edinburgh
4 * Copyright (c) 2021 IBM Corporation
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions are
9 * met: redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer;
11 * redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution;
14 * neither the name of the copyright holders nor the names of its
15 * contributors may be used to endorse or promote products derived from
16 * this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 */
30
31 #include "arch/power/process.hh"
32
33 #include "arch/power/isa_traits.hh"
34 #include "arch/power/types.hh"
35 #include "base/loader/elf_object.hh"
36 #include "base/loader/object_file.hh"
37 #include "base/logging.hh"
38 #include "cpu/thread_context.hh"
39 #include "debug/Stack.hh"
40 #include "mem/page_table.hh"
41 #include "params/Process.hh"
42 #include "sim/aux_vector.hh"
43 #include "sim/process_impl.hh"
44 #include "sim/syscall_return.hh"
45 #include "sim/system.hh"
46
47 using namespace PowerISA;
48
49 PowerProcess::PowerProcess(
50 const ProcessParams &params, ::Loader::ObjectFile *objFile)
51 : Process(params,
52 new EmulationPageTable(params.name, params.pid, PageBytes),
53 objFile)
54 {
55 fatal_if(params.useArchPT, "Arch page tables not implemented.");
56 // Set up break point (Top of Heap)
57 Addr brk_point = image.maxAddr();
58 brk_point = roundUp(brk_point, PageBytes);
59
60 Addr stack_base = 0xbf000000L;
61
62 Addr max_stack_size = 8 * 1024 * 1024;
63
64 // Set pointer for next thread stack. Reserve 8M for main stack.
65 Addr next_thread_stack_base = stack_base - max_stack_size;
66
67 // Set up region for mmaps. For now, start at bottom of kuseg space.
68 Addr mmap_end = 0x70000000L;
69
70 memState = std::make_shared<MemState>(
71 this, brk_point, stack_base, max_stack_size,
72 next_thread_stack_base, mmap_end);
73 }
74
75 void
76 PowerProcess::initState()
77 {
78 Process::initState();
79
80 if (objFile->getArch() == ::Loader::Power)
81 argsInit<uint32_t>(PageBytes);
82 else
83 argsInit<uint64_t>(PageBytes);
84
85 // Fix up entry point and symbol table for 64-bit ELF ABI v1
86 if (objFile->getOpSys() != ::Loader::LinuxPower64ABIv1)
87 return;
88
89 // Fix entry point address and the base TOC pointer by looking the
90 // the function descriptor in the .opd section
91 Addr entryPoint, tocBase;
92 ByteOrder byteOrder = objFile->getByteOrder();
93 ThreadContext *tc = system->threads[contextIds[0]];
94
95 // The first doubleword of the descriptor contains the address of the
96 // entry point of the function
97 initVirtMem->readBlob(getStartPC(), &entryPoint, sizeof(Addr));
98
99 // Update the PC state
100 auto pc = tc->pcState();
101 pc.byteOrder(byteOrder);
102 pc.set(gtoh(entryPoint, byteOrder));
103 tc->pcState(pc);
104
105 // The second doubleword of the descriptor contains the TOC base
106 // address for the function
107 initVirtMem->readBlob(getStartPC() + 8, &tocBase, sizeof(Addr));
108 tc->setIntReg(TOCPointerReg, gtoh(tocBase, byteOrder));
109
110 // Fix symbol table entries as they would otherwise point to the
111 // function descriptor rather than the actual entry point address
112 auto *symbolTable = new ::Loader::SymbolTable;
113
114 for (auto sym : ::Loader::debugSymbolTable) {
115 Addr entry;
116 ::Loader::Symbol symbol = sym;
117
118 // Try to read entry point from function descriptor
119 if (initVirtMem->tryReadBlob(sym.address, &entry, sizeof(Addr)))
120 symbol.address = gtoh(entry, byteOrder);
121
122 symbolTable->insert(symbol);
123 }
124
125 // Replace the current debug symbol table
126 ::Loader::debugSymbolTable.clear();
127 ::Loader::debugSymbolTable.insert(*symbolTable);
128 delete symbolTable;
129 }
130
131 template <typename IntType>
132 void
133 PowerProcess::argsInit(int pageSize)
134 {
135 int intSize = sizeof(IntType);
136 ByteOrder byteOrder = objFile->getByteOrder();
137 bool is64bit = (objFile->getArch() == ::Loader::Power64);
138 bool isLittleEndian = (byteOrder == ByteOrder::little);
139 std::vector<AuxVector<IntType>> auxv;
140
141 std::string filename;
142 if (argv.size() < 1)
143 filename = "";
144 else
145 filename = argv[0];
146
147 //We want 16 byte alignment
148 uint64_t align = 16;
149
150 // load object file into target memory
151 image.write(*initVirtMem);
152 interpImage.write(*initVirtMem);
153
154 //Setup the auxilliary vectors. These will already have endian conversion.
155 //Auxilliary vectors are loaded only for elf formatted executables.
156 auto *elfObject = dynamic_cast<::Loader::ElfObject *>(objFile);
157 if (elfObject) {
158 IntType features = PPC_FEATURE_32;
159
160 // Check if running in 64-bit mode
161 if (is64bit)
162 features |= PPC_FEATURE_64;
163
164 // Check if running in little endian mode
165 if (isLittleEndian)
166 features |= PPC_FEATURE_PPC_LE | PPC_FEATURE_TRUE_LE;
167
168 //Bits which describe the system hardware capabilities
169 //XXX Figure out what these should be
170 auxv.emplace_back(M5_AT_HWCAP, features);
171 //The system page size
172 auxv.emplace_back(M5_AT_PAGESZ, pageSize);
173 //Frequency at which times() increments
174 auxv.emplace_back(M5_AT_CLKTCK, 0x64);
175 // For statically linked executables, this is the virtual address of
176 // the program header tables if they appear in the executable image
177 auxv.emplace_back(M5_AT_PHDR, elfObject->programHeaderTable());
178 // This is the size of a program header entry from the elf file.
179 auxv.emplace_back(M5_AT_PHENT, elfObject->programHeaderSize());
180 // This is the number of program headers from the original elf file.
181 auxv.emplace_back(M5_AT_PHNUM, elfObject->programHeaderCount());
182 // This is the base address of the ELF interpreter; it should be
183 // zero for static executables or contain the base address for
184 // dynamic executables.
185 auxv.emplace_back(M5_AT_BASE, getBias());
186 //XXX Figure out what this should be.
187 auxv.emplace_back(M5_AT_FLAGS, 0);
188 //The entry point to the program
189 auxv.emplace_back(M5_AT_ENTRY, objFile->entryPoint());
190 //Different user and group IDs
191 auxv.emplace_back(M5_AT_UID, uid());
192 auxv.emplace_back(M5_AT_EUID, euid());
193 auxv.emplace_back(M5_AT_GID, gid());
194 auxv.emplace_back(M5_AT_EGID, egid());
195 //Whether to enable "secure mode" in the executable
196 auxv.emplace_back(M5_AT_SECURE, 0);
197 //The address of 16 "random" bytes
198 auxv.emplace_back(M5_AT_RANDOM, 0);
199 //The filename of the program
200 auxv.emplace_back(M5_AT_EXECFN, 0);
201 //The string "v51" with unknown meaning
202 auxv.emplace_back(M5_AT_PLATFORM, 0);
203 }
204
205 //Figure out how big the initial stack nedes to be
206
207 // A sentry NULL void pointer at the top of the stack.
208 int sentry_size = intSize;
209
210 std::string platform = "v51";
211 int platform_size = platform.size() + 1;
212
213 // The aux vectors are put on the stack in two groups. The first group are
214 // the vectors that are generated as the elf is loaded. The second group
215 // are the ones that were computed ahead of time and include the platform
216 // string.
217 int aux_data_size = filename.size() + 1;
218
219 const int numRandomBytes = 16;
220 aux_data_size += numRandomBytes;
221
222 int env_data_size = 0;
223 for (int i = 0; i < envp.size(); ++i) {
224 env_data_size += envp[i].size() + 1;
225 }
226 int arg_data_size = 0;
227 for (int i = 0; i < argv.size(); ++i) {
228 arg_data_size += argv[i].size() + 1;
229 }
230
231 int info_block_size =
232 sentry_size + env_data_size + arg_data_size +
233 aux_data_size + platform_size;
234
235 //Each auxilliary vector is two 4 byte words
236 int aux_array_size = intSize * 2 * (auxv.size() + 1);
237
238 int envp_array_size = intSize * (envp.size() + 1);
239 int argv_array_size = intSize * (argv.size() + 1);
240
241 int argc_size = intSize;
242
243 //Figure out the size of the contents of the actual initial frame
244 int frame_size =
245 info_block_size +
246 aux_array_size +
247 envp_array_size +
248 argv_array_size +
249 argc_size;
250
251 //There needs to be padding after the auxiliary vector data so that the
252 //very bottom of the stack is aligned properly.
253 int partial_size = frame_size;
254 int aligned_partial_size = roundUp(partial_size, align);
255 int aux_padding = aligned_partial_size - partial_size;
256
257 int space_needed = frame_size + aux_padding;
258
259 Addr stack_min = memState->getStackBase() - space_needed;
260 stack_min = roundDown(stack_min, align);
261
262 memState->setStackSize(memState->getStackBase() - stack_min);
263
264 // map memory
265 memState->mapRegion(roundDown(stack_min, pageSize),
266 roundUp(memState->getStackSize(), pageSize), "stack");
267
268 // map out initial stack contents
269 IntType sentry_base = memState->getStackBase() - sentry_size;
270 IntType aux_data_base = sentry_base - aux_data_size;
271 IntType env_data_base = aux_data_base - env_data_size;
272 IntType arg_data_base = env_data_base - arg_data_size;
273 IntType platform_base = arg_data_base - platform_size;
274 IntType auxv_array_base = platform_base - aux_array_size - aux_padding;
275 IntType envp_array_base = auxv_array_base - envp_array_size;
276 IntType argv_array_base = envp_array_base - argv_array_size;
277 IntType argc_base = argv_array_base - argc_size;
278
279 DPRINTF(Stack, "The addresses of items on the initial stack:\n");
280 DPRINTF(Stack, "0x%x - aux data\n", aux_data_base);
281 DPRINTF(Stack, "0x%x - env data\n", env_data_base);
282 DPRINTF(Stack, "0x%x - arg data\n", arg_data_base);
283 DPRINTF(Stack, "0x%x - platform base\n", platform_base);
284 DPRINTF(Stack, "0x%x - auxv array\n", auxv_array_base);
285 DPRINTF(Stack, "0x%x - envp array\n", envp_array_base);
286 DPRINTF(Stack, "0x%x - argv array\n", argv_array_base);
287 DPRINTF(Stack, "0x%x - argc \n", argc_base);
288 DPRINTF(Stack, "0x%x - stack min\n", stack_min);
289
290 // write contents to stack
291
292 // figure out argc
293 IntType argc = argv.size();
294 IntType guestArgc = htog(argc, byteOrder);
295
296 //Write out the sentry void *
297 IntType sentry_NULL = 0;
298 initVirtMem->writeBlob(sentry_base, &sentry_NULL, sentry_size);
299
300 //Fix up the aux vectors which point to other data
301 for (int i = auxv.size() - 1; i >= 0; i--) {
302 if (auxv[i].type == M5_AT_PLATFORM) {
303 auxv[i].val = platform_base;
304 initVirtMem->writeString(platform_base, platform.c_str());
305 } else if (auxv[i].type == M5_AT_EXECFN) {
306 auxv[i].val = aux_data_base + numRandomBytes;
307 initVirtMem->writeString(aux_data_base, filename.c_str());
308 } else if (auxv[i].type == M5_AT_RANDOM) {
309 auxv[i].val = aux_data_base;
310 }
311 }
312
313 //Copy the aux stuff
314 Addr auxv_array_end = auxv_array_base;
315 for (const auto &aux: auxv) {
316 initVirtMem->write(auxv_array_end, aux, byteOrder);
317 auxv_array_end += sizeof(aux);
318 }
319 //Write out the terminating zeroed auxilliary vector
320 const AuxVector<uint64_t> zero(0, 0);
321 initVirtMem->write(auxv_array_end, zero);
322 auxv_array_end += sizeof(zero);
323
324 copyStringArray(envp, envp_array_base, env_data_base,
325 byteOrder, *initVirtMem);
326 copyStringArray(argv, argv_array_base, arg_data_base,
327 byteOrder, *initVirtMem);
328
329 initVirtMem->writeBlob(argc_base, &guestArgc, intSize);
330
331 ThreadContext *tc = system->threads[contextIds[0]];
332
333 //Set the stack pointer register
334 tc->setIntReg(StackPointerReg, stack_min);
335
336 //Reset the special-purpose registers
337 for (int i = 0; i < NumMiscRegs; i++)
338 tc->setMiscRegNoEffect(i, 0);
339
340 //Set the machine status for a typical userspace
341 Msr msr = 0;
342 msr.sf = is64bit;
343 msr.hv = 1;
344 msr.ee = 1;
345 msr.pr = 1;
346 msr.me = 1;
347 msr.ir = 1;
348 msr.dr = 1;
349 msr.ri = 1;
350 msr.le = isLittleEndian;
351 tc->setMiscReg(MISCREG_MSR, msr);
352
353 auto pc = tc->pcState();
354 pc.set(getStartPC());
355 pc.byteOrder(byteOrder);
356 tc->pcState(pc);
357
358 //Align the "stack_min" to a page boundary.
359 memState->setStackMin(roundDown(stack_min, pageSize));
360 }