# Linux Kernel Module Cheat

##### 24.8.2.2. m5ops instructions interface

Let’s study how the gem5 m5 executable uses them:

- `include/gem5/asm/generic/m5ops.h`: defines the magic constants that represent the instructions

- `util/m5/m5op_arm_A64.S`: use the magic constants that represent the instructions using C preprocessor magic

- `util/m5/m5.c`: the actual executable. Gets linked to `m5op_arm_A64.S` which defines a function for each m5op.

We notice that there are two different implementations for each arch:

- magic instructions, which don’t exist in the corresponding arch

- magic memory addresses on a given page: m5ops magic addresses

Then, in aarch64 magic instructions for example, the lines:

    .macro  m5op_func, name, func, subfunc
            .globl \name
            \name:
            .long 0xff000110 | (\func << 16) | (\subfunc << 12)
            ret

define a simple function function for each m5op. Here we see that:

- `0xff000110` is a base mask for the magic non-existing instruction

- `\func` and `\subfunc` are OR-applied on top of the base mask, and define m5op this is.

  Those values will loop over the magic constants defined in `m5ops.h` with the deferred preprocessor idiom.

  For example, `exit` is `0x21` due to:

      #define M5OP_EXIT               0x21

Finally, `m5.c` calls the defined functions as in:

    m5_exit(ints[0]);

Therefore, the runtime "argument" that gets passed to the instruction, e.g. the delay in ticks until the exit for `m5 exit`, gets passed directly through the aarch64 calling convention.

Keep in mind that for all archs, `m5.c` does the calls with 64-bit integers:

    uint64_t ints[2] = {0,0};
    parse_int_args(argc, argv, ints, argc);
    m5_fail(ints[1], ints[0]);

Therefore, for example:

- aarch64 uses `x0` for the first argument and `x1` for the second, since each is 64 bits log already

- arm uses `r0` and `r1` for the first argument, and `r2` and `r3` for the second, since each register is only 32 bits long

That convention specifies that `x0` to `x7` contain the function arguments, so `x0` contains the first argument, and `x1` the second.

In our `m5ops` example, we just hardcode everything in the assembly one-liners we are producing.

We ignore the `\subfunc` since it is always 0 on the ops that interest us.