# Linux Kernel Module Cheat
The perfect emulation setup to study and develop the <<linux-kernel>> v5.9.2, kernel modules, <<qemu-buildroot-setup,QEMU>>, <<gem5-buildroot-setup,gem5>> and x86_64, ARMv7 and ARMv8 <<userland-assembly,userland>> and <<baremetal-setup,baremetal>> assembly, <<c,ANSI C>>, <<cpp,C++>> and <<posix,POSIX>>. <<gdb>> and <<kgdb>> just work. Powered by <<about-the-qemu-buildroot-setup,Buildroot>> and <<about-the-baremetal-setup,crosstool-NG>>. Highly automated. Thoroughly documented. Automated <<test-this-repo,tests>>.

### 7.4. Init environment

Documented at https://www.kernel.org/doc/html/v5.9/admin-guide/kernel-parameters.html:

> The kernel parses parameters from the kernel command line up to "--"; if it doesn’t recognize a parameter and it doesn’t contain a '.', the parameter gets passed to init: parameters with '=' go into init’s environment, others are passed as command line arguments to init. Everything after "--" is passed as an argument to init.

And you can try it out with our userland/linux/init_env_poweroff.c program:

    ./run --kernel-cli 'init=/lkmc/linux/init_env_poweroff.out loglevel=8 go_in_env=val1 with_dot.before=val2' \
          --kernel-cli-after-dash 'go_in_arg=val3 with_dot.after=val4 zxcv'

From the generated QEMU command, we see that the kernel CLI at LKMC 69f5745d3df11d5c741551009df86ea6c61a09cf now contains (or at least would if it weren’t for https://github.com/cirosantilli/linux-kernel-module-cheat/issues/110 oh God), manually indented for readability:

    <6>[    0.000000] Command line: root=/dev/vda nopat console_msg_format=syslog nokaslr norandmaps panic=-1 printk.devkmsg=on printk.time=y rw
      init=/lkmc/linux/init_env_poweroff.out loglevel=8 go_in_env=val1 with_dot.before=val2 -- go_in_arg=val3 with_dot.after=val4 zxcv

and the init program outputs:

    <6>[    2.728992] Run /lkmc/linux/init_env_poweroff.out as init process
    <7>[    2.729587]   with arguments:
    <7>[    2.729820]     /lkmc/linux/init_env_poweroff.out
    <7>[    2.730085]     lkmc_home=/lkmc
    <7>[    2.730259]     go_in_arg=val3
    <7>[    2.730432]     with_dot.after=val4
    <7>[    2.730623]     zxcv
    <7>[    2.730767]   with environment:
    <7>[    2.730960]     HOME=/
    <7>[    2.731115]     TERM=linux
    <7>[    2.731267]     go_in_env=val

Tested as of the Linux kernel v5.7 and possibly earlier, boot also shows the init arguments and environment very clearly when using printk at `loglevel=8`, which is a great addition:

    <6>[    2.777265] Run /lkmc/linux/init_env_poweroff.out as init process
    <7>[    2.777729]   with arguments:
    <7>[    2.777953]     /lkmc/linux/init_env_poweroff.out
    <7>[    2.778212]     lkmc_home=/lkmc
    <7>[    2.778391]     go_in_arg=val2
    <7>[    2.778554]     zxcv
    <7>[    2.778705]   with environment:
    <7>[    2.778901]     HOME=/
    <7>[    2.779065]     TERM=linux
    <7>[    2.779223]     go_in_env=val1

As we can see, the passing of environment variables to init is a bit wonky:

- `init` and `loglevel` didn’t go because they were recognized

- `go_in_env` went because it wasn’t

so things can always break in future kernel releases…​ The only way to guard from this a bit is to use some unique prefix and hope the kernel never decides to use it. We of course use `lkmc_*` for our variables.

And it is also impossible to pass environment variables that contain dots in them: our `with_dot.before` is simply gone. Not a common use case, but still, quite insane.

- init arguments

- init environment env

- BusyBox shell init environment