3.10.1.1. CONFIG_PID_IN_CONTEXTIDR

https://stackoverflow.com/questions/54133479/accessing-logical-software-thread-id-in-gem5 on ARM the kernel can store an indication of PID in the CONTEXTIDR_EL1 register, making that much easier to observe from simulators.

In particular, gem5 prints that number out by default on ExecAll messages!

./build-linux --arch aarch64 --linux-build-id CONFIG_PID_IN_CONTEXTIDR --config 'CONFIG_PID_IN_CONTEXTIDR=y'
# Checkpoint run.
./run --arch aarch64 --emulator gem5 --linux-build-id CONFIG_PID_IN_CONTEXTIDR --eval './gem5.sh'
# Trace run.
./run \
  --arch aarch64 \
  --emulator gem5 \
  --gem5-readfile 'posix/getpid.out; posix/getpid.out' \
  --gem5-restore 1 \
  --linux-build-id CONFIG_PID_IN_CONTEXTIDR \
  --trace FmtFlag,ExecAll,-ExecSymbol \
;

The terminal runs both programs which output their PID to stdout:

pid=44
pid=45

By quickly inspecting the trace.txt file, we immediately notice that the system.cpu: A<n> part of the logs, which used to always be system.cpu: A0, now has a few different values! Nice!

We can briefly summarize those values by removing repetitions:

cut -d' ' -f4 "$(./getvar --arch aarch64 --emulator gem5 trace_txt_file)" | uniq -c

gives:

  97227 A39
 147476 A38
 222052 A40
      1 terminal
1117724 A40
  27529 A31
  43868 A40
  27487 A31
 138349 A40
  13781 A38
 231246 A40
  25536 A38
  28337 A40
 214799 A38
 963561 A41
  92603 A38
  27511 A31
 224384 A38
 564949 A42
 182360 A38
 729009 A43
   8398 A23
  20200 A10
 636848 A43
 187995 A44
  27529 A31
  70071 A44
  16981 A0
 623806 A44
  16981 A0
 139319 A44
  24487 A0
 174986 A44
  25420 A0
  89611 A44
  16981 A0
 183184 A44
  24728 A0
  89608 A44
  17226 A0
 899075 A44
  24974 A0
 250608 A44
 137700 A43
1497997 A45
 227485 A43
 138147 A38
 482646 A46

I’m not smart enough to be able to deduce all of those IDs, but we can at least see that:

  • A44 and A45 are there as expected from stdout!

  • A39 must be the end of the execution of m5 checkpoint

  • so we guess that A38 is the shell as it comes next

  • the weird "terminal" line is 336969745500: system.terminal: attach terminal 0

  • which is the shell PID? I should have printed that as well :-)

  • why are there so many other PIDs? This was supposed to be a silent system without daemons!

  • A0 is presumably the kernel. However we see process switches without going into A0, so I’m not sure how, it appears to count kernel instructions as part of processes

  • A46 has to be the m5 exit call

Or if you want to have some real fun, try: baremetal/arch/aarch64/contextidr_el1.c:

./run --arch aarch64 --emulator gem5 --baremetal baremetal/arch/aarch64/contextidr_el1.c --trace-insts-stdout

in which we directly set the register ourselves! Output excerpt:

  31500: system.cpu: A0 T0 : @main+12    :   ldr   x0, [sp, #12]      : MemRead :  D=0x0000000000000001 A=0x82fffffc  flags=(IsInteger|IsMemRef|IsLoad)
  32000: system.cpu: A1 T0 : @main+16    :   msr   contextidr_el1, x0 : IntAlu :  D=0x0000000000000001  flags=(IsInteger|IsSerializeAfter|IsNonSpeculative)
  32500: system.cpu: A1 T0 : @main+20    :   ldr   x0, [sp, #12]      : MemRead :  D=0x0000000000000001 A=0x82fffffc  flags=(IsInteger|IsMemRef|IsLoad)
  33000: system.cpu: A1 T0 : @main+24    :   add   w0, w0, #1         : IntAlu :  D=0x0000000000000002  flags=(IsInteger)
  33500: system.cpu: A1 T0 : @main+28    :   str   x0, [sp, #12]      : MemWrite :  D=0x0000000000000002 A=0x82fffffc  flags=(IsInteger|IsMemRef|IsStore)
  34000: system.cpu: A1 T0 : @main+32    :   ldr   x0, [sp, #12]      : MemRead :  D=0x0000000000000002 A=0x82fffffc  flags=(IsInteger|IsMemRef|IsLoad)
  34500: system.cpu: A1 T0 : @main+36    :   subs   w0, #9            : IntAlu :  D=0x0000000000000000  flags=(IsInteger)
  35000: system.cpu: A1 T0 : @main+40    :   b.le   <main+12>         : IntAlu :   flags=(IsControl|IsDirectControl|IsCondControl)
  35500: system.cpu: A1 T0 : @main+12    :   ldr   x0, [sp, #12]      : MemRead :  D=0x0000000000000002 A=0x82fffffc  flags=(IsInteger|IsMemRef|IsLoad)
  36000: system.cpu: A2 T0 : @main+16    :   msr   contextidr_el1, x0 : IntAlu :  D=0x0000000000000002  flags=(IsInteger|IsSerializeAfter|IsNonSpeculative)
  36500: system.cpu: A2 T0 : @main+20    :   ldr   x0, [sp, #12]      : MemRead :  D=0x0000000000000002 A=0x82fffffc  flags=(IsInteger|IsMemRef|IsLoad)
  37000: system.cpu: A2 T0 : @main+24    :   add   w0, w0, #1         : IntAlu :  D=0x0000000000000003  flags=(IsInteger)
  37500: system.cpu: A2 T0 : @main+28    :   str   x0, [sp, #12]      : MemWrite :  D=0x0000000000000003 A=0x82fffffc  flags=(IsInteger|IsMemRef|IsStore)
  38000: system.cpu: A2 T0 : @main+32    :   ldr   x0, [sp, #12]      : MemRead :  D=0x0000000000000003 A=0x82fffffc  flags=(IsInteger|IsMemRef|IsLoad)
  38500: system.cpu: A2 T0 : @main+36    :   subs   w0, #9            : IntAlu :  D=0x0000000000000000  flags=(IsInteger)
  39000: system.cpu: A2 T0 : @main+40    :   b.le   <main+12>         : IntAlu :   flags=(IsControl|IsDirectControl|IsCondControl)
  39500: system.cpu: A2 T0 : @main+12    :   ldr   x0, [sp, #12]      : MemRead :  D=0x0000000000000003 A=0x82fffffc  flags=(IsInteger|IsMemRef|IsLoad)
  40000: system.cpu: A3 T0 : @main+16    :   msr   contextidr_el1, x0 : IntAlu :  D=0x0000000000000003  flags=(IsInteger|IsSerializeAfter|IsNonSpeculative)

ARMv8 architecture reference manual db D13.2.27 "CONTEXTIDR_EL1, Context ID Register (EL1)" documents CONTEXTIDR_EL1 as:

Identifies the current Process Identifier.

The value of the whole of this register is called the Context ID and is used by:

  • The debug logic, for Linked and Unlinked Context ID matching.

  • The trace logic, to identify the current process.

The significance of this register is for debug and trace use only.

Tested on 145769fc387dc5ee63ec82e55e6b131d9c968538 + 1.