mem-cache: Add multiple eviction stats
[gem5.git] / src / arch / arm / process.cc
1 /*
2 * Copyright (c) 2010, 2012, 2017-2018 ARM Limited
3 * All rights reserved
4 *
5 * The license below extends only to copyright in the software and shall
6 * not be construed as granting a license to any other intellectual
7 * property including but not limited to intellectual property relating
8 * to a hardware implementation of the functionality of the software
9 * licensed hereunder. You may use the software subject to the license
10 * terms below provided that you ensure that this notice is replicated
11 * unmodified and in its entirety in all distributions of the software,
12 * modified or unmodified, in source code or in binary form.
13 *
14 * Copyright (c) 2007-2008 The Florida State University
15 * All rights reserved.
16 *
17 * Redistribution and use in source and binary forms, with or without
18 * modification, are permitted provided that the following conditions are
19 * met: redistributions of source code must retain the above copyright
20 * notice, this list of conditions and the following disclaimer;
21 * redistributions in binary form must reproduce the above copyright
22 * notice, this list of conditions and the following disclaimer in the
23 * documentation and/or other materials provided with the distribution;
24 * neither the name of the copyright holders nor the names of its
25 * contributors may be used to endorse or promote products derived from
26 * this software without specific prior written permission.
27 *
28 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
29 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
30 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
31 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
32 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
33 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
34 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
35 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
36 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
37 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
38 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
39 *
40 * Authors: Stephen Hines
41 * Ali Saidi
42 */
43
44 #include "arch/arm/process.hh"
45
46 #include "arch/arm/isa_traits.hh"
47 #include "arch/arm/types.hh"
48 #include "base/loader/elf_object.hh"
49 #include "base/loader/object_file.hh"
50 #include "base/logging.hh"
51 #include "cpu/thread_context.hh"
52 #include "debug/Stack.hh"
53 #include "mem/page_table.hh"
54 #include "params/Process.hh"
55 #include "sim/aux_vector.hh"
56 #include "sim/byteswap.hh"
57 #include "sim/process_impl.hh"
58 #include "sim/syscall_return.hh"
59 #include "sim/system.hh"
60
61 using namespace std;
62 using namespace ArmISA;
63
64 ArmProcess::ArmProcess(ProcessParams *params, ObjectFile *objFile,
65 ObjectFile::Arch _arch)
66 : Process(params,
67 new EmulationPageTable(params->name, params->pid, PageBytes),
68 objFile),
69 arch(_arch)
70 {
71 fatal_if(params->useArchPT, "Arch page tables not implemented.");
72 }
73
74 ArmProcess32::ArmProcess32(ProcessParams *params, ObjectFile *objFile,
75 ObjectFile::Arch _arch)
76 : ArmProcess(params, objFile, _arch)
77 {
78 Addr brk_point = roundUp(image.maxAddr(), PageBytes);
79 Addr stack_base = 0xbf000000L;
80 Addr max_stack_size = 8 * 1024 * 1024;
81 Addr next_thread_stack_base = stack_base - max_stack_size;
82 Addr mmap_end = 0x40000000L;
83
84 memState = make_shared<MemState>(brk_point, stack_base, max_stack_size,
85 next_thread_stack_base, mmap_end);
86 }
87
88 ArmProcess64::ArmProcess64(ProcessParams *params, ObjectFile *objFile,
89 ObjectFile::Arch _arch)
90 : ArmProcess(params, objFile, _arch)
91 {
92 Addr brk_point = roundUp(image.maxAddr(), PageBytes);
93 Addr stack_base = 0x7fffff0000L;
94 Addr max_stack_size = 8 * 1024 * 1024;
95 Addr next_thread_stack_base = stack_base - max_stack_size;
96 Addr mmap_end = 0x4000000000L;
97
98 memState = make_shared<MemState>(brk_point, stack_base, max_stack_size,
99 next_thread_stack_base, mmap_end);
100 }
101
102 void
103 ArmProcess32::initState()
104 {
105 Process::initState();
106 argsInit<uint32_t>(PageBytes, INTREG_SP);
107 for (int i = 0; i < contextIds.size(); i++) {
108 ThreadContext * tc = system->getThreadContext(contextIds[i]);
109 CPACR cpacr = tc->readMiscReg(MISCREG_CPACR);
110 // Enable the floating point coprocessors.
111 cpacr.cp10 = 0x3;
112 cpacr.cp11 = 0x3;
113 tc->setMiscReg(MISCREG_CPACR, cpacr);
114 // Generically enable floating point support.
115 FPEXC fpexc = tc->readMiscReg(MISCREG_FPEXC);
116 fpexc.en = 1;
117 tc->setMiscReg(MISCREG_FPEXC, fpexc);
118 }
119 }
120
121 void
122 ArmProcess64::initState()
123 {
124 Process::initState();
125 argsInit<uint64_t>(PageBytes, INTREG_SP0);
126 for (int i = 0; i < contextIds.size(); i++) {
127 ThreadContext * tc = system->getThreadContext(contextIds[i]);
128 CPSR cpsr = tc->readMiscReg(MISCREG_CPSR);
129 cpsr.mode = MODE_EL0T;
130 tc->setMiscReg(MISCREG_CPSR, cpsr);
131 CPACR cpacr = tc->readMiscReg(MISCREG_CPACR_EL1);
132 // Enable the floating point coprocessors.
133 cpacr.cp10 = 0x3;
134 cpacr.cp11 = 0x3;
135 // Enable SVE.
136 cpacr.zen = 0x3;
137 tc->setMiscReg(MISCREG_CPACR_EL1, cpacr);
138 // Generically enable floating point support.
139 FPEXC fpexc = tc->readMiscReg(MISCREG_FPEXC);
140 fpexc.en = 1;
141 tc->setMiscReg(MISCREG_FPEXC, fpexc);
142 }
143 }
144
145 uint32_t
146 ArmProcess32::armHwcapImpl() const
147 {
148 enum ArmCpuFeature {
149 Arm_Swp = 1 << 0,
150 Arm_Half = 1 << 1,
151 Arm_Thumb = 1 << 2,
152 Arm_26Bit = 1 << 3,
153 Arm_FastMult = 1 << 4,
154 Arm_Fpa = 1 << 5,
155 Arm_Vfp = 1 << 6,
156 Arm_Edsp = 1 << 7,
157 Arm_Java = 1 << 8,
158 Arm_Iwmmxt = 1 << 9,
159 Arm_Crunch = 1 << 10,
160 Arm_ThumbEE = 1 << 11,
161 Arm_Neon = 1 << 12,
162 Arm_Vfpv3 = 1 << 13,
163 Arm_Vfpv3d16 = 1 << 14
164 };
165
166 return Arm_Swp | Arm_Half | Arm_Thumb | Arm_FastMult |
167 Arm_Vfp | Arm_Edsp | Arm_ThumbEE | Arm_Neon |
168 Arm_Vfpv3 | Arm_Vfpv3d16;
169 }
170
171 uint32_t
172 ArmProcess64::armHwcapImpl() const
173 {
174 // In order to know what these flags mean, please refer to Linux
175 // /Documentation/arm64/elf_hwcaps.txt text file.
176 enum ArmCpuFeature {
177 Arm_Fp = 1 << 0,
178 Arm_Asimd = 1 << 1,
179 Arm_Evtstrm = 1 << 2,
180 Arm_Aes = 1 << 3,
181 Arm_Pmull = 1 << 4,
182 Arm_Sha1 = 1 << 5,
183 Arm_Sha2 = 1 << 6,
184 Arm_Crc32 = 1 << 7,
185 Arm_Atomics = 1 << 8,
186 Arm_Fphp = 1 << 9,
187 Arm_Asimdhp = 1 << 10,
188 Arm_Cpuid = 1 << 11,
189 Arm_Asimdrdm = 1 << 12,
190 Arm_Jscvt = 1 << 13,
191 Arm_Fcma = 1 << 14,
192 Arm_Lrcpc = 1 << 15,
193 Arm_Dcpop = 1 << 16,
194 Arm_Sha3 = 1 << 17,
195 Arm_Sm3 = 1 << 18,
196 Arm_Sm4 = 1 << 19,
197 Arm_Asimddp = 1 << 20,
198 Arm_Sha512 = 1 << 21,
199 Arm_Sve = 1 << 22,
200 Arm_Asimdfhm = 1 << 23,
201 Arm_Dit = 1 << 24,
202 Arm_Uscat = 1 << 25,
203 Arm_Ilrcpc = 1 << 26,
204 Arm_Flagm = 1 << 27
205 };
206
207 uint32_t hwcap = 0;
208
209 ThreadContext *tc = system->getThreadContext(contextIds[0]);
210
211 const AA64PFR0 pf_r0 = tc->readMiscReg(MISCREG_ID_AA64PFR0_EL1);
212
213 hwcap |= (pf_r0.fp == 0) ? Arm_Fp : 0;
214 hwcap |= (pf_r0.fp == 1) ? Arm_Fphp | Arm_Fp : 0;
215 hwcap |= (pf_r0.advsimd == 0) ? Arm_Asimd : 0;
216 hwcap |= (pf_r0.advsimd == 1) ? Arm_Asimdhp | Arm_Asimd : 0;
217 hwcap |= (pf_r0.sve >= 1) ? Arm_Sve : 0;
218 hwcap |= (pf_r0.dit >= 1) ? Arm_Dit : 0;
219
220 const AA64ISAR0 isa_r0 = tc->readMiscReg(MISCREG_ID_AA64ISAR0_EL1);
221
222 hwcap |= (isa_r0.aes >= 1) ? Arm_Aes : 0;
223 hwcap |= (isa_r0.aes >= 2) ? Arm_Pmull : 0;
224 hwcap |= (isa_r0.sha1 >= 1) ? Arm_Sha1 : 0;
225 hwcap |= (isa_r0.sha2 >= 1) ? Arm_Sha2 : 0;
226 hwcap |= (isa_r0.sha2 >= 2) ? Arm_Sha512 : 0;
227 hwcap |= (isa_r0.crc32 >= 1) ? Arm_Crc32 : 0;
228 hwcap |= (isa_r0.atomic >= 1) ? Arm_Atomics : 0;
229 hwcap |= (isa_r0.rdm >= 1) ? Arm_Asimdrdm : 0;
230 hwcap |= (isa_r0.sha3 >= 1) ? Arm_Sha3 : 0;
231 hwcap |= (isa_r0.sm3 >= 1) ? Arm_Sm3 : 0;
232 hwcap |= (isa_r0.sm4 >= 1) ? Arm_Sm4 : 0;
233 hwcap |= (isa_r0.dp >= 1) ? Arm_Asimddp : 0;
234 hwcap |= (isa_r0.fhm >= 1) ? Arm_Asimdfhm : 0;
235 hwcap |= (isa_r0.ts >= 1) ? Arm_Flagm : 0;
236
237 const AA64ISAR1 isa_r1 = tc->readMiscReg(MISCREG_ID_AA64ISAR1_EL1);
238
239 hwcap |= (isa_r1.dpb >= 1) ? Arm_Dcpop : 0;
240 hwcap |= (isa_r1.jscvt >= 1) ? Arm_Jscvt : 0;
241 hwcap |= (isa_r1.fcma >= 1) ? Arm_Fcma : 0;
242 hwcap |= (isa_r1.lrcpc >= 1) ? Arm_Lrcpc : 0;
243 hwcap |= (isa_r1.lrcpc >= 2) ? Arm_Ilrcpc : 0;
244
245 const AA64MMFR2 mm_fr2 = tc->readMiscReg(MISCREG_ID_AA64MMFR2_EL1);
246
247 hwcap |= (mm_fr2.at >= 1) ? Arm_Uscat : 0;
248
249 return hwcap;
250 }
251
252 template <class IntType>
253 void
254 ArmProcess::argsInit(int pageSize, IntRegIndex spIndex)
255 {
256 int intSize = sizeof(IntType);
257
258 std::vector<AuxVector<IntType>> auxv;
259
260 string filename;
261 if (argv.size() < 1)
262 filename = "";
263 else
264 filename = argv[0];
265
266 //We want 16 byte alignment
267 uint64_t align = 16;
268
269 //Setup the auxilliary vectors. These will already have endian conversion.
270 //Auxilliary vectors are loaded only for elf formatted executables.
271 ElfObject * elfObject = dynamic_cast<ElfObject *>(objFile);
272 if (elfObject) {
273
274 if (objFile->getOpSys() == ObjectFile::Linux) {
275 IntType features = armHwcap<IntType>();
276
277 //Bits which describe the system hardware capabilities
278 //XXX Figure out what these should be
279 auxv.emplace_back(M5_AT_HWCAP, features);
280 //Frequency at which times() increments
281 auxv.emplace_back(M5_AT_CLKTCK, 0x64);
282 //Whether to enable "secure mode" in the executable
283 auxv.emplace_back(M5_AT_SECURE, 0);
284 // Pointer to 16 bytes of random data
285 auxv.emplace_back(M5_AT_RANDOM, 0);
286 //The filename of the program
287 auxv.emplace_back(M5_AT_EXECFN, 0);
288 //The string "v71" -- ARM v7 architecture
289 auxv.emplace_back(M5_AT_PLATFORM, 0);
290 }
291
292 //The system page size
293 auxv.emplace_back(M5_AT_PAGESZ, ArmISA::PageBytes);
294 // For statically linked executables, this is the virtual address of
295 // the program header tables if they appear in the executable image
296 auxv.emplace_back(M5_AT_PHDR, elfObject->programHeaderTable());
297 // This is the size of a program header entry from the elf file.
298 auxv.emplace_back(M5_AT_PHENT, elfObject->programHeaderSize());
299 // This is the number of program headers from the original elf file.
300 auxv.emplace_back(M5_AT_PHNUM, elfObject->programHeaderCount());
301 // This is the base address of the ELF interpreter; it should be
302 // zero for static executables or contain the base address for
303 // dynamic executables.
304 auxv.emplace_back(M5_AT_BASE, getBias());
305 //XXX Figure out what this should be.
306 auxv.emplace_back(M5_AT_FLAGS, 0);
307 //The entry point to the program
308 auxv.emplace_back(M5_AT_ENTRY, objFile->entryPoint());
309 //Different user and group IDs
310 auxv.emplace_back(M5_AT_UID, uid());
311 auxv.emplace_back(M5_AT_EUID, euid());
312 auxv.emplace_back(M5_AT_GID, gid());
313 auxv.emplace_back(M5_AT_EGID, egid());
314 }
315
316 //Figure out how big the initial stack nedes to be
317
318 // A sentry NULL void pointer at the top of the stack.
319 int sentry_size = intSize;
320
321 string platform = "v71";
322 int platform_size = platform.size() + 1;
323
324 // Bytes for AT_RANDOM above, we'll just keep them 0
325 int aux_random_size = 16; // as per the specification
326
327 // The aux vectors are put on the stack in two groups. The first group are
328 // the vectors that are generated as the elf is loaded. The second group
329 // are the ones that were computed ahead of time and include the platform
330 // string.
331 int aux_data_size = filename.size() + 1;
332
333 int env_data_size = 0;
334 for (int i = 0; i < envp.size(); ++i) {
335 env_data_size += envp[i].size() + 1;
336 }
337 int arg_data_size = 0;
338 for (int i = 0; i < argv.size(); ++i) {
339 arg_data_size += argv[i].size() + 1;
340 }
341
342 int info_block_size =
343 sentry_size + env_data_size + arg_data_size +
344 aux_data_size + platform_size + aux_random_size;
345
346 //Each auxilliary vector is two 4 byte words
347 int aux_array_size = intSize * 2 * (auxv.size() + 1);
348
349 int envp_array_size = intSize * (envp.size() + 1);
350 int argv_array_size = intSize * (argv.size() + 1);
351
352 int argc_size = intSize;
353
354 //Figure out the size of the contents of the actual initial frame
355 int frame_size =
356 info_block_size +
357 aux_array_size +
358 envp_array_size +
359 argv_array_size +
360 argc_size;
361
362 //There needs to be padding after the auxiliary vector data so that the
363 //very bottom of the stack is aligned properly.
364 int partial_size = frame_size;
365 int aligned_partial_size = roundUp(partial_size, align);
366 int aux_padding = aligned_partial_size - partial_size;
367
368 int space_needed = frame_size + aux_padding;
369
370 memState->setStackMin(memState->getStackBase() - space_needed);
371 memState->setStackMin(roundDown(memState->getStackMin(), align));
372 memState->setStackSize(memState->getStackBase() - memState->getStackMin());
373
374 // map memory
375 allocateMem(roundDown(memState->getStackMin(), pageSize),
376 roundUp(memState->getStackSize(), pageSize));
377
378 // map out initial stack contents
379 IntType sentry_base = memState->getStackBase() - sentry_size;
380 IntType aux_data_base = sentry_base - aux_data_size;
381 IntType env_data_base = aux_data_base - env_data_size;
382 IntType arg_data_base = env_data_base - arg_data_size;
383 IntType platform_base = arg_data_base - platform_size;
384 IntType aux_random_base = platform_base - aux_random_size;
385 IntType auxv_array_base = aux_random_base - aux_array_size - aux_padding;
386 IntType envp_array_base = auxv_array_base - envp_array_size;
387 IntType argv_array_base = envp_array_base - argv_array_size;
388 IntType argc_base = argv_array_base - argc_size;
389
390 DPRINTF(Stack, "The addresses of items on the initial stack:\n");
391 DPRINTF(Stack, "0x%x - aux data\n", aux_data_base);
392 DPRINTF(Stack, "0x%x - env data\n", env_data_base);
393 DPRINTF(Stack, "0x%x - arg data\n", arg_data_base);
394 DPRINTF(Stack, "0x%x - random data\n", aux_random_base);
395 DPRINTF(Stack, "0x%x - platform base\n", platform_base);
396 DPRINTF(Stack, "0x%x - auxv array\n", auxv_array_base);
397 DPRINTF(Stack, "0x%x - envp array\n", envp_array_base);
398 DPRINTF(Stack, "0x%x - argv array\n", argv_array_base);
399 DPRINTF(Stack, "0x%x - argc \n", argc_base);
400 DPRINTF(Stack, "0x%x - stack min\n", memState->getStackMin());
401
402 // write contents to stack
403
404 // figure out argc
405 IntType argc = argv.size();
406 IntType guestArgc = htole(argc);
407
408 //Write out the sentry void *
409 IntType sentry_NULL = 0;
410 initVirtMem.writeBlob(sentry_base, &sentry_NULL, sentry_size);
411
412 //Fix up the aux vectors which point to other data
413 for (int i = auxv.size() - 1; i >= 0; i--) {
414 if (auxv[i].type == M5_AT_PLATFORM) {
415 auxv[i].val = platform_base;
416 initVirtMem.writeString(platform_base, platform.c_str());
417 } else if (auxv[i].type == M5_AT_EXECFN) {
418 auxv[i].val = aux_data_base;
419 initVirtMem.writeString(aux_data_base, filename.c_str());
420 } else if (auxv[i].type == M5_AT_RANDOM) {
421 auxv[i].val = aux_random_base;
422 // Just leave the value 0, we don't want randomness
423 }
424 }
425
426 //Copy the aux stuff
427 Addr auxv_array_end = auxv_array_base;
428 for (const auto &aux: auxv) {
429 initVirtMem.write(auxv_array_end, aux, GuestByteOrder);
430 auxv_array_end += sizeof(aux);
431 }
432 //Write out the terminating zeroed auxillary vector
433 const AuxVector<IntType> zero(0, 0);
434 initVirtMem.write(auxv_array_end, zero);
435 auxv_array_end += sizeof(zero);
436
437 copyStringArray(envp, envp_array_base, env_data_base,
438 LittleEndianByteOrder, initVirtMem);
439 copyStringArray(argv, argv_array_base, arg_data_base,
440 LittleEndianByteOrder, initVirtMem);
441
442 initVirtMem.writeBlob(argc_base, &guestArgc, intSize);
443
444 ThreadContext *tc = system->getThreadContext(contextIds[0]);
445 //Set the stack pointer register
446 tc->setIntReg(spIndex, memState->getStackMin());
447 //A pointer to a function to run when the program exits. We'll set this
448 //to zero explicitly to make sure this isn't used.
449 tc->setIntReg(ArgumentReg0, 0);
450 //Set argument regs 1 and 2 to argv[0] and envp[0] respectively
451 if (argv.size() > 0) {
452 tc->setIntReg(ArgumentReg1, arg_data_base + arg_data_size -
453 argv[argv.size() - 1].size() - 1);
454 } else {
455 tc->setIntReg(ArgumentReg1, 0);
456 }
457 if (envp.size() > 0) {
458 tc->setIntReg(ArgumentReg2, env_data_base + env_data_size -
459 envp[envp.size() - 1].size() - 1);
460 } else {
461 tc->setIntReg(ArgumentReg2, 0);
462 }
463
464 PCState pc;
465 pc.thumb(arch == ObjectFile::Thumb);
466 pc.nextThumb(pc.thumb());
467 pc.aarch64(arch == ObjectFile::Arm64);
468 pc.nextAArch64(pc.aarch64());
469 pc.set(getStartPC() & ~mask(1));
470 tc->pcState(pc);
471
472 //Align the "stackMin" to a page boundary.
473 memState->setStackMin(roundDown(memState->getStackMin(), pageSize));
474 }
475
476 RegVal
477 ArmProcess32::getSyscallArg(ThreadContext *tc, int &i)
478 {
479 assert(i < 6);
480 return tc->readIntReg(ArgumentReg0 + i++);
481 }
482
483 RegVal
484 ArmProcess64::getSyscallArg(ThreadContext *tc, int &i)
485 {
486 assert(i < 8);
487 return tc->readIntReg(ArgumentReg0 + i++);
488 }
489
490 RegVal
491 ArmProcess32::getSyscallArg(ThreadContext *tc, int &i, int width)
492 {
493 assert(width == 32 || width == 64);
494 if (width == 32)
495 return getSyscallArg(tc, i);
496
497 // 64 bit arguments are passed starting in an even register
498 if (i % 2 != 0)
499 i++;
500
501 // Registers r0-r6 can be used
502 assert(i < 5);
503 uint64_t val;
504 val = tc->readIntReg(ArgumentReg0 + i++);
505 val |= ((uint64_t)tc->readIntReg(ArgumentReg0 + i++) << 32);
506 return val;
507 }
508
509 RegVal
510 ArmProcess64::getSyscallArg(ThreadContext *tc, int &i, int width)
511 {
512 return getSyscallArg(tc, i);
513 }
514
515 void
516 ArmProcess32::setSyscallReturn(ThreadContext *tc, SyscallReturn sysret)
517 {
518
519 if (objFile->getOpSys() == ObjectFile::FreeBSD) {
520 // Decode return value
521 if (sysret.encodedValue() >= 0)
522 // FreeBSD checks the carry bit to determine if syscall is succeeded
523 tc->setCCReg(CCREG_C, 0);
524 else {
525 sysret = -sysret.encodedValue();
526 }
527 }
528
529 tc->setIntReg(ReturnValueReg, sysret.encodedValue());
530 }
531
532 void
533 ArmProcess64::setSyscallReturn(ThreadContext *tc, SyscallReturn sysret)
534 {
535
536 if (objFile->getOpSys() == ObjectFile::FreeBSD) {
537 // Decode return value
538 if (sysret.encodedValue() >= 0)
539 // FreeBSD checks the carry bit to determine if syscall is succeeded
540 tc->setCCReg(CCREG_C, 0);
541 else {
542 sysret = -sysret.encodedValue();
543 }
544 }
545
546 tc->setIntReg(ReturnValueReg, sysret.encodedValue());
547 }