24.22.4.1. gem5 event queue AtomicSimpleCPU syscall emulation freestanding example analysis

Let’s now analyze every single event on a minimal gem5 syscall emulation mode in the simplest CPU that we have:

./run \
  --arch aarch64 \
  --emulator gem5 \
  --userland userland/arch/aarch64/freestanding/linux/hello.S \
  --trace Event,ExecAll,FmtFlag \
  --trace-stdout \
;

which gives:

      0: Event: AtomicSimpleCPU tick.wrapped_function_event: EventFunctionWrapped 39 scheduled @ 0
**** REAL SIMULATION ****
      0: Event: Event_70: generic 70 scheduled @ 0
info: Entering event queue @ 0.  Starting simulation...
      0: Event: Event_70: generic 70 rescheduled @ 18446744073709551615
      0: Event: AtomicSimpleCPU tick.wrapped_function_event: EventFunctionWrapped 39 executed @ 0
      0: ExecEnable: system.cpu: A0 T0 : @asm_main_after_prologue    :   movz   x0, #1, #0        : IntAlu :  D=0x0000000000000001  flags=(IsInteger)
      0: Event: AtomicSimpleCPU tick.wrapped_function_event: EventFunctionWrapped 39 rescheduled @ 500
    500: Event: AtomicSimpleCPU tick.wrapped_function_event: EventFunctionWrapped 39 executed @ 500
    500: ExecEnable: system.cpu: A0 T0 : @asm_main_after_prologue+4    :   adr   x1, #28            : IntAlu :  D=0x0000000000400098  flags=(IsInteger)
    500: Event: AtomicSimpleCPU tick.wrapped_function_event: EventFunctionWrapped 39 rescheduled @ 1000
   1000: Event: AtomicSimpleCPU tick.wrapped_function_event: EventFunctionWrapped 39 executed @ 1000
   1000: ExecEnable: system.cpu: A0 T0 : @asm_main_after_prologue+8    :   ldr   w2, #4194464       : MemRead :  D=0x0000000000000006 A=0x4000a0  flags=(IsInteger|IsMemRef|IsLoad)
   1000: Event: AtomicSimpleCPU tick.wrapped_function_event: EventFunctionWrapped 39 rescheduled @ 1500
   1500: Event: AtomicSimpleCPU tick.wrapped_function_event: EventFunctionWrapped 39 executed @ 1500
   1500: ExecEnable: system.cpu: A0 T0 : @asm_main_after_prologue+12    :   movz   x8, #64, #0       : IntAlu :  D=0x0000000000000040  flags=(IsInteger)
   1500: Event: AtomicSimpleCPU tick.wrapped_function_event: EventFunctionWrapped 39 rescheduled @ 2000
   2000: Event: AtomicSimpleCPU tick.wrapped_function_event: EventFunctionWrapped 39 executed @ 2000
   2000: ExecEnable: system.cpu: A0 T0 : @asm_main_after_prologue+16    :   svc   #0x0               : IntAlu :   flags=(IsSerializeAfter|IsNonSpeculative|IsSyscall)
hello
   2000: Event: AtomicSimpleCPU tick.wrapped_function_event: EventFunctionWrapped 39 rescheduled @ 2500
   2500: Event: AtomicSimpleCPU tick.wrapped_function_event: EventFunctionWrapped 39 executed @ 2500
   2500: ExecEnable: system.cpu: A0 T0 : @asm_main_after_prologue+20    :   movz   x0, #0, #0        : IntAlu :  D=0x0000000000000000  flags=(IsInteger)
   2500: Event: AtomicSimpleCPU tick.wrapped_function_event: EventFunctionWrapped 39 rescheduled @ 3000
   3000: Event: AtomicSimpleCPU tick.wrapped_function_event: EventFunctionWrapped 39 executed @ 3000
   3000: ExecEnable: system.cpu: A0 T0 : @asm_main_after_prologue+24    :   movz   x8, #93, #0       : IntAlu :  D=0x000000000000005d  flags=(IsInteger)
   3000: Event: AtomicSimpleCPU tick.wrapped_function_event: EventFunctionWrapped 39 rescheduled @ 3500
   3500: Event: AtomicSimpleCPU tick.wrapped_function_event: EventFunctionWrapped 39 executed @ 3500
   3500: ExecEnable: system.cpu: A0 T0 : @asm_main_after_prologue+28    :   svc   #0x0               : IntAlu :   flags=(IsSerializeAfter|IsNonSpeculative|IsSyscall)
   3500: Event: Event_71: generic 71 scheduled @ 3500
   3500: Event: Event_71: generic 71 executed @ 3500

On the event trace, we can first see:

0: Event: AtomicSimpleCPU tick.wrapped_function_event: EventFunctionWrapped 39 scheduled @ 0

This schedules a tick event for time 0, and leads to the first clock tick.

Then:

0: Event: Event_70: generic 70 scheduled @ 0
0: Event: Event_70: generic 70 rescheduled @ 18446744073709551615

schedules the end of time event for time 0, which is later rescheduled to the actual end of time.

At:

0: Event: AtomicSimpleCPU tick.wrapped_function_event: EventFunctionWrapped 39 executed @ 0
0: ExecEnable: system.cpu: A0 T0 : @asm_main_after_prologue    :   movz   x0, #1, #0        : IntAlu :  D=0x0000000000000001  flags=(IsInteger)
0: Event: AtomicSimpleCPU tick.wrapped_function_event: EventFunctionWrapped 39 rescheduled @ 500

the tick event happens, the instruction runs, and then the instruction is rescheduled in 500 time units. This is done at the end of AtomicSimpleCPU::tick():

if (_status != Idle)
    reschedule(tickEvent, curTick() + latency, true);

At:

3500: ExecEnable: system.cpu: A0 T0 : @asm_main_after_prologue+28    :   svc   #0x0               : IntAlu :   flags=(IsSerializeAfter|IsNonSpeculative|IsSyscall)
3500: Event: Event_71: generic 71 scheduled @ 3500
3500: Event: Event_71: generic 71 executed @ 3500

the exit system call is called, and then it schedules an exit evit, which gets executed and the simulation ends.

We guess then that Event_71 comes from the SE implementation of the exit syscall, so let’s just confirm, the trace contains:

exitSimLoop() at sim_events.cc:97 0x5555594746e0
exitImpl() at syscall_emul.cc:215 0x55555948c046
exitFunc() at syscall_emul.cc:225 0x55555948c147
SyscallDesc::doSyscall() at syscall_desc.cc:72 0x5555594949b6
Process::syscall() at process.cc:401 0x555559484717
SimpleThread::syscall() at 0x555559558059
ArmISA::SupervisorCall::invoke() at faults.cc:856 0x5555572950d7
BaseSimpleCPU::advancePC() at base.cc:681 0x555559083133
AtomicSimpleCPU::tick() at atomic.cc:757 0x55555907834c

and exitSimLoop() does:

new GlobalSimLoopExitEvent(when + simQuantum, message, exit_code, repeat);

Tested in gem5 12c917de54145d2d50260035ba7fa614e25317a3.