<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom"><title>The Synthesist</title><id>https://cooldev.in/feeds/tags/linux-kernel.xml</id><subtitle>Tag: linux-kernel</subtitle><updated>2026-07-02T14:42:28Z</updated><link href="https://cooldev.in/feeds/tags/linux-kernel.xml" rel="self" /><link href="https://cooldev.in" /><entry><title>Starting-the-Kernel-Journey—My-LKMP-Experience</title><id>https://cooldev.in/starting-the-kernel-journeymy-lkmp-experience.html</id><author><name>Gopi Krishna Menon</name><email>krishnagopi487@cooldev.in</email></author><updated>2025-12-08T00:00:00Z</updated><link href="https://cooldev.in/starting-the-kernel-journeymy-lkmp-experience.html" rel="alternate" /><content type="html">&lt;blockquote&gt;&lt;p&gt;Bound by the shackles of Knowledge and fear,&lt;br /&gt;Linux Kernel had me rolling my tears.&lt;/p&gt;&lt;p&gt;Liberation I see was nowhere near,&lt;br /&gt;My love for the kernel seemed to disappear.&lt;/p&gt;&lt;p&gt;Then came the LKMP, that ignited the spark,&lt;br /&gt;Melting those shackles to free me at last.&lt;/p&gt;&lt;p&gt;Now I am free and over my fears,&lt;br /&gt;Patching the kernel without any tears.&lt;/p&gt;&lt;ul&gt;&lt;li&gt;GK&lt;/li&gt;&lt;/ul&gt;&lt;/blockquote&gt;&lt;p&gt;Before I write about my experience, I would like to thank my mentors
Shuah Khan, David Hunter and Khalid Aziz for providing me this
opportunity to become a part of the LKMP - 2025 Fall Program and this
wonderful kernel community.&lt;/p&gt;&lt;h2&gt;What is LKMP?&lt;/h2&gt;&lt;p&gt;LKMP stands for Linux Kernel Mentorship Program. Its actually a remote
mentorship program that is conducted by Linux Foundation along with some
of the best Kernel Engineers and Maintainers from the community to train
the next generation of Linux Kernel developers.&lt;/p&gt;&lt;p&gt;The core objectives of the program are:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;Provide remote learning oppurtunity to the aspiring Linux Kernel
developers.&lt;/li&gt;&lt;li&gt;Infuse new talent into the Linux Kernel community.&lt;/li&gt;&lt;li&gt;Make the kernel more secure and sustainable.&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;There are a couple of variants of LKMP program but the one that is
currently running is the Bug Fixing variant (Unpaid). You can find more
information about the program here :
&lt;a href=&quot;https://wiki.linuxfoundation.org/lkmp&quot;&gt;lkmp&lt;/a&gt;&lt;/p&gt;&lt;h2&gt;Acceptance Into The Program&lt;/h2&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;Once you have created an account at
&lt;a href=&quot;https://mentorship.lfx.linuxfoundation.org&quot;&gt;LFX portal&lt;/a&gt; and
enrolled in the program, you will be given a set of tasks, that you
will have to complete within the stipulated deadline (around 3 weeks).
These tasks might include writing kernel modules, analyzing syzbot
bugs and sending kernel patches.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;Along with that you will be also required to complete
&lt;a href=&quot;https://training.linuxfoundation.org/training/a-beginners-guide-to-linux-kernel-development-lfd103/&quot;&gt;LFD103
Course&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;Once you have submitted all the tasks and completed the course, wait
until the deadline :)&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;blockquote&gt;&lt;p&gt;Please take the tasks pretty seriously. This time only 74
out 486 applicants were selected i.e around 15%. So make sure to give it
your best.&lt;/p&gt;&lt;/blockquote&gt;&lt;h2&gt;Mentorship Info&lt;/h2&gt;&lt;h3&gt;Communication&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;For communicating with mentors and peers, we use discord&lt;/li&gt;&lt;li&gt;Patches and their reviews happen over the email.&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;Before getting selected, I began using &lt;a href=&quot;https://neomutt.org/&quot;&gt;neomutt&lt;/a&gt;
for working with emails. I didnt like the existing themes in neomutt, so
decided to submit a theme based on the ayu-dark color palette. That got
merged. Therefore if you like ayu-dark theme, make sure to try it using
the steps mentioned &lt;a href=&quot;https://neomutt.org/contrib/colorschemes&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;&lt;p&gt;Its just amazing that for a project Like linux kernel, email acts as the
primary way of communication. Initially i was skeptical about how all of
this works, but once you start using it, you see the real power of
emails. Everything from sending patches, reviewing patches, applying
patches becomes so much easier using email. Emails are just extremely
flexible.&lt;/p&gt;&lt;h3&gt;Meetings&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;There is a 1hr meeting scheduled everyweek (office hours), where you
can clarify your doubts, get your patches reviewed. In the first few
office hours, Shuah will also take some tutorial sessions on tools
like csope/ctags, cregit, kselftests, syzbot, backporting etc.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;Please make sure to attend those tutorial sessions. They will make
your life easier and help you understand different aspects of kernel
development including setting up a workflow, debugging, testing,
finding bugs, backporting etc.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;These office hours also allow you to understand how your peers are
tackling problems. I was highly inspired by some of my peers during
this process and this helped me fix my own problems as well.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;David Hunter also conducted an additional session on Bug hunting in
the kernel, which I found really effective. This was a hands on
session where we discovered new bugs together. Thanks a lot David for
this session.&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;blockquote&gt;&lt;p&gt;Note Its just amazing, how much patience our mentors had when we
got stuck on issues. Shuah and David both went above and beyond trying
to help us fix our problems. They did not solve our issues directly, but
they made sure to understand the problem and guide us in the right path.
Again I cannot emphasize enough, how much that is helpful for mentees.
Thanks a lot for helping us, inspiring us and giving us the confidence
to submit our patches.&lt;/p&gt;&lt;/blockquote&gt;&lt;h2&gt;Community&lt;/h2&gt;&lt;p&gt;The linux kernel community is beginner friendly in nature. Since we
communicate through emails, there are mailing lists for each subsystem
in the kernel. You can find a list of these mailing lists at
&lt;a href=&quot;https://lore.kernel.org&quot;&gt;lore.kernel.org&lt;/a&gt;&lt;/p&gt;&lt;p&gt;lore is an extremely useful web archive as you can find every patch in
there. You can also see the threads associated with those patches. Along
with that lore also provides you ways to search for patches that touch
perticular file or are specific to perticular author, which can be
extremely helpful.&lt;/p&gt;&lt;p&gt;Learning to interact with the community is a key part of kernel
development. In order to improve your communication skills, you can go
through the lore threads of the subsystem that you are interested in.&lt;/p&gt;&lt;p&gt;In addition, I also took
&lt;a href=&quot;https://trainingportal.linuxfoundation.org/courses/remote-work-at-scale-lfc114&quot;&gt;LFC114
Course&lt;/a&gt; offered by linux foundation to help me improve in this area.&lt;/p&gt;&lt;h2&gt;My Patches&lt;/h2&gt;&lt;p&gt;Although I do have some experience working with the kernel as a part of
a research project, I still consider myself as a novice in actual kernel
development.&lt;/p&gt;&lt;p&gt;Therefore I decided to start slow and focus on submitting three kinds of
patches in the kernel,&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;Fixing documentation build faliures&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;Fixing static analysis bugs reported by the compiler and internal
kernel tools&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;Fixing syzbot bugs&lt;/p&gt;&lt;p&gt;git log --author=&amp;quot;Gopi Krishna Menon&amp;quot; --since=“2025-08-01” --pretty --format=oneline
a5160af78be7fcf3ade6caab0a14e349560c96d7 usb: raw-gadget: cap raw_io transfer length to KMALLOC_MAX_SIZE
89194773f5738a0617240ac92b190fbd553e58bc drm/msm: Add NULL check in vm_op_enqueue()
9efb297c520f392ab04bc45544a03770c98c3798 hwmon: (gpd-fan) Fix compilation error in non-ACPI builds
02227b97a8d3ae01bcf12e5e1b5cb6cca9439875 selftests: tty: add tty_tiocsti_test to .gitignore
77cd9210271556aff955551b3e2ef0ae8a2691bd docs: trusted-encrypted: fix htmldocs build error
96b546c241b11a97ba1247580208c554458e7866 Documentation/rtla: rename common_xxx.rst files to common_xxx.txt
7e8f305a081e22ce81aab7f7b9ce01437cbd38b3 docs/zh_CN: Fix malformed table
989ed3cad2fdb7921bf0f9f0f730e1bb065946c2 docs/zh_TW: Fix malformed table
03faea8466713f04a522c52c386124755be960bc selftests/net: add tcp_port_share to .gitignore
d496b6f42eb0455caf5d8cb30cf1f01b7fc2a747 mtd: cfi: use struct_size() helper for cfiq allocation
cb0c5a60a6f7dd7f35fa5b46fd04dfb66b37fc1e docs: perf: Fujitsu: Fix htmldocs build warnings and errors
5fdb877b4916a1eb2b2c85018c2311855893405b selftests/futex: Fix typos and grammar in futex_priv_hash
05f297c3e39f62f579458a59ab1b1c8bf3fc1c51 KVM: selftests: fix minor typo in cpumodel_subfuncs
70d476b63a1494337f2b9fec1e9b1cab2e6116d3 Documentation/rv: Fix minor typo in monitor_synthesis page
0e6bb6888791656c3973f26da3288323524573c0 docs: folio_queue: Fix minor typo in folio_queue page&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;There were a number of other dynamic analysis bugs that I attempted as
well.&lt;/p&gt;&lt;p&gt;&lt;img src=&quot;/images/lkmp/additional_syzbot.png&quot; alt=&quot;img&quot; /&gt;&lt;/p&gt;&lt;p&gt;Some of them I almost solved, but the kernel developers sent patches
before me 🙂&lt;/p&gt;&lt;h2&gt;Things to remember as a kernel developer&lt;/h2&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;Test all your patches. Shuah mentioned this in almost every meeting
multiple times. Test your changes extensively and use tools like
kselftest to ensure that nothing breaks. On top of this, mention your
testing methodology in the email itself when you send the patch.
Untested code can result in regressions which can be a headache for
everyone including maintainers, authors and the user themselves.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;If you dont have the hardware to test the patch, avoid making that
patch. Patches can be marked as RFT (Request for Testing), but still
its advised not to work on those kinds of patches.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;Avoid top posting in emails and instead use interleaved posting or
bottom posting when replying.
(&lt;a href=&quot;https://en.wikipedia.org/wiki/Posting_style&quot;&gt;Posting Style&lt;/a&gt;)&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;Initially, we can work on different subsystems for understanding the
workflow but after sometime, you should choose a subsystem of your
interest and try to gravitate towards that. This will help you make
bigger contributions to the kernel.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;Write the commit messages in
&lt;a href=&quot;https://www.kernel.org/doc/html/v4.10/process/submitting-patches.html#describe-your-changes&quot;&gt;Imperative
Tone&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;If your patch is not accepted yet, wait for a few weeks. Maintainers
are also humans and therefore sometimes things might take time to get
reviewed. Look out for the merge window as well. If you dont get a
reply for say 2-3 weeks, gently ping the reviewers asking if they
could look at the patch. (Just saying ping is a bad idea).&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;Read the documentation. Usually every subsystem has a slightly
different way of accepting patches (they might require specific tags,
specific tests to run etc). In that case check the mailing list for
that perticular subsystem and see how others have done that.&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;h2&gt;How to find Bugs in the kernel?&lt;/h2&gt;&lt;ul&gt;&lt;li&gt;Looking for Documentation Bugs? Run &lt;code&gt;make html-docs&lt;/code&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;Looking for Static Analysis Bugs?&lt;/p&gt;&lt;ul&gt;&lt;li&gt;Use Sparse, Smatch, Coccinelle&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;Looking for Dynamic Analysis Bugs?&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;&lt;a href=&quot;https://syzkaller.appspot.com/upstream&quot;&gt;syzbot&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;Additional tools can be found
&lt;a href=&quot;https://www.kernel.org/doc/html/v6.1/dev-tools/testing-overview.html#dynamic-analysis-tools&quot;&gt;here&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;There is one more way. randconfig (For static analysis and build related
bugs)&lt;/p&gt;&lt;p&gt;Here is a small script that will run randconfig n number of times and
capture the problematic kernel builds.&lt;/p&gt;&lt;p&gt;In simple terms&lt;/p&gt;&lt;ul&gt;&lt;li&gt;First it generates a random config for the architecture&lt;/li&gt;&lt;li&gt;Then it builds the kernel using this config&lt;/li&gt;&lt;li&gt;If the build breaks or config has some issues, it logs down the config
and the build output so that a human like me can review them and use
them for fixing those bugs.&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;Note : Sometimes this does result in false positives. So be careful
about the errors that you are investigating.&lt;/p&gt;&lt;p&gt;randconfig builds should atleast compile. If they fail to do so, that
means there is some undeclared dependency and could be a problem in some
configuration for some users.&lt;/p&gt;&lt;p&gt;Infact kernel's CI service also does something similar I believe.&lt;/p&gt;&lt;pre&gt;&lt;code&gt;#!/bin/bash
# ================================================
# Sequential randconfig builds for linux-next(x86-64)
# ================================================

BUILD_COUNT=10
ARCH=&amp;quot;x86_64&amp;quot;
BASE_DIR=/linux_work
LINUX_NEXT_DIR=$BASE_DIR/linux
DATE=`date +&amp;quot;%d-%m-%y&amp;quot;`
LOG_DIR=$BASE_DIR/randconfig-logs/$DATE
CONFIG_FILE=.config
REMOTE=origin
BRANCH=master
NPROC=$(( $(nproc) / 2 ))

# Create log dir if not available
mkdir -p $LOG_DIR
echo &amp;quot;Starting $BUILD_COUNT sequential randconfig builds for $ARCH...&amp;quot;
echo &amp;quot;Logs will be stored in $LOG_DIR&amp;quot;

# Get the latest commits
cd $LINUX_NEXT_DIR
git fetch $REMOTE 
git reset --hard $REMOTE/$BRANCH
COMMIT_INFO=$(git log -1 --oneline)

# All sequential builds
for i in $(seq 1 $BUILD_COUNT); do
    LOG_FILE=build_log.log
    CONFIG_GEN_LOG_FILE=config_gen_log.log
    CONFIG_GEN_LOG_DIR=$LOG_DIR/config-gen-log

    echo &amp;quot;=============================&amp;quot;
    echo &amp;quot;Build $i / $BUILD_COUNT&amp;quot;
    echo &amp;quot;=============================&amp;quot;

    # Clean old build artifacts
    make mrproper &amp;gt; /dev/null

    # Remove previous logs.
    rm -rf $LOG_FILE
    rm -rf $CONFIG_GEN_LOG_FILE


    # Add the commit info in config_gen_log
    echo $COMMIT_INFO &amp;gt; $CONFIG_GEN_LOG_FILE
    # Generate random config
    make ARCH=$ARCH randconfig &amp;gt;&amp;gt; $CONFIG_GEN_LOG_FILE 2&amp;gt;&amp;amp;1 


    # For unique config name
    CONFIG_HASH=$(sha1sum .config | cut -c1-8)

    # Do we have warning or error when generating config? Log seperately
    if grep -iq &amp;quot;error:&amp;quot; &amp;quot;$CONFIG_GEN_LOG_FILE&amp;quot; || grep -iq &amp;quot;warning:&amp;quot; &amp;quot;$CONFIG_GEN_LOG_FILE&amp;quot;; then
      mkdir -p $CONFIG_GEN_LOG_DIR
      # Copy over the config into config-gen-log folder as config-hash
      cp $CONFIG_FILE $CONFIG_GEN_LOG_DIR/config-$CONFIG_HASH
    fi

    # Add the commit info in build log
    echo $COMMIT_INFO &amp;gt; $LOG_FILE
    # Build the kernel
    make -j$NPROC &amp;gt;&amp;gt; $LOG_FILE 2&amp;gt;&amp;amp;1

    # Check for errors or warnings
    if grep -iq &amp;quot;error:&amp;quot; &amp;quot;$LOG_FILE&amp;quot; || grep -iq &amp;quot;warning:&amp;quot; &amp;quot;$LOG_FILE&amp;quot;; then
      # We store the config file and build log
      ERROR_CONFIG_FILENAME=error_config
      ERROR_BUILD_LOG_FILENAME=error_build_log.log

      # We store the above files in a seperate dir
      ERROR_LOG_DIR=$LOG_DIR/config-$CONFIG_HASH
      mkdir -p $ERROR_LOG_DIR

      # Store the config and build log in here
      mv $CONFIG_FILE $ERROR_LOG_DIR/$ERROR_CONFIG_FILENAME
      mv $LOG_FILE $ERROR_LOG_DIR/$ERROR_BUILD_LOG_FILENAME
      echo &amp;quot;❌  Build $i failed. See $ERROR_LOG_DIR&amp;quot;
    else
      echo &amp;quot;✅  Build $i completed successfully.&amp;quot;
    fi
done

echo &amp;quot;All $BUILD_COUNT builds finished.&amp;quot;
echo &amp;quot;Logs are in $LOG_DIR&amp;quot;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The output will look something like this where both the config and the
output can be used to reproduce the error.&lt;/p&gt;&lt;p&gt;&lt;img src=&quot;/images/lkmp/ErrorBuild.png&quot; alt=&quot;img&quot; /&gt;&lt;/p&gt;&lt;ul&gt;&lt;li&gt;Here &lt;code&gt;error_config&lt;/code&gt; represents the kernel config that generates this
issue&lt;/li&gt;&lt;li&gt;&lt;code&gt;error_build_log&lt;/code&gt; represents the build log which shows the type of
error encountered&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;Bonus Tip : If you wish to run this for different architectures, you can
contact the guys over at &lt;a href=&quot;https://gcc.gnu.org/wiki/CompileFarm&quot;&gt;GCC
Compile Farm Project&lt;/a&gt; and request access to their machines for doing
testing.&lt;/p&gt;&lt;h2&gt;Future&lt;/h2&gt;&lt;p&gt;I have found my interest in the USB and MM subsystem and wish to make
substantial contributions in these areas in the Linux Kernel. Also I
would like to become a maintainer at some point in the linux kernel.&lt;/p&gt;&lt;p&gt;If you are interested to get involved with the kernel community and
aspire to be a linux kernel developer, I would highly recommend applying
for the Linux Kernel Mentorship Program.&lt;/p&gt;&lt;p&gt;Happy Coding !!&lt;/p&gt;&lt;blockquote&gt;&lt;p&gt;It's not that we don't dare do things because they are difficult;
rather, they are difficult because we don't dare – Seneca. (From
Richard Stallman's personal
&lt;a href=&quot;https://www.stallman.org/quotes.html&quot;&gt;site&lt;/a&gt;)&lt;/p&gt;&lt;/blockquote&gt;</content></entry><entry><title>Dissecting a Simple Linux Kernel Module</title><id>https://cooldev.in/dissecting-a-simple-linux-kernel-module.html</id><author><name>Gopi Krishna Menon</name><email>krishnagopi487@cooldev.in</email></author><updated>2025-07-30T19:00:00Z</updated><link href="https://cooldev.in/dissecting-a-simple-linux-kernel-module.html" rel="alternate" /><content type="html">&lt;p&gt;Dissecting a Simple Linux Kernel Module&lt;/p&gt;&lt;h1&gt;Dissecting a Simple Linux Kernel Module&lt;/h1&gt;&lt;p&gt;Hi, In this short article we will explore the internal structure of a
simple hello world module in the linux kernel, breaking down its anatomy
and understanding how it integrates with the kernel.&lt;/p&gt;&lt;h2&gt;Environment&lt;/h2&gt;&lt;ul&gt;&lt;li&gt;&lt;strong&gt;Kernel Version&lt;/strong&gt; : 6.16.0&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Build Toolchain&lt;/strong&gt; : clang 18, LLVM 18&lt;/li&gt;&lt;li&gt;&lt;strong&gt;OS&lt;/strong&gt; : Ubuntu 22.04 / Nixos (Any distro will work)&lt;/li&gt;&lt;/ul&gt;&lt;h2&gt;Basics&lt;/h2&gt;&lt;p&gt;The Linux kernel is monolithic in nature. Monolithic kernels lack the
extensibility and modularity, which can make the kernel bloated and
difficult to manage. Linux kernel solves this problem with kernel
modules.&lt;/p&gt;&lt;p&gt;A kernel module is an object file containing code that can be loaded at
runtime and can be used to extend the functionality of the kernel. When
a module is no longer needed, it can be automatically unloaded, thereby
reducing the memory footprint. Modules give several advantages to the
kernel, such as extensibility, modularity, low memory footprint, faster
compilation, etc. Most of the device drivers in the kernel are
implemented in the form of modules, which contributes significantly to
the modularity and maintainability of the kernel.&lt;/p&gt;&lt;p&gt;Internally, the kernel consists of a loader that, when requested, can
load and map this object file into its own address space. Once mapped,
the module can call kernel symbols just like any other part of the
kernel.&lt;/p&gt;&lt;p&gt;Having a modular kernel also allows companies to provide their drivers
in the form of proprietary binary blobs. This way, the company can apply
its licenses to the source code and is not obligated to release the
source code. Whether it's a good thing or a bad thing is a different
topic (in terms of philosophy, security, etc.), but I guess companies
have their reason for doing this.&lt;/p&gt;&lt;h2&gt;Source Code&lt;/h2&gt;&lt;p&gt;Let us now examine the traditional &lt;code&gt;hello_world&lt;/code&gt; module and understand
what happens internally.&lt;/p&gt;&lt;pre&gt;&lt;code&gt;// SPDX-License-Identifier: GPL-2.0
#include &amp;lt;linux/module.h&amp;gt;

MODULE_DESCRIPTION(&amp;quot;A simple hello world module&amp;quot;);
MODULE_AUTHOR(&amp;quot;Gopi Krishna Menon&amp;quot;);
MODULE_LICENSE(&amp;quot;GPL&amp;quot;);

static int __init hello_mod_init(void)
{
        pr_info(&amp;quot;%s: Hello World\n&amp;quot;, KBUILD_MODNAME);
        return 0;
}

static void __exit hello_mod_exit(void)
{
        pr_info(&amp;quot;%s: Unloading hello_mod\n&amp;quot;, KBUILD_MODNAME);
}

module_init(hello_mod_init);
module_exit(hello_mod_exit);&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The code illustrates the fundamental structure of a kernel module. Its
key components are :&lt;/p&gt;&lt;ul&gt;&lt;li&gt;License Identifier (SPDX Identifier)&lt;/li&gt;&lt;li&gt;HeaderFile (module.h)&lt;/li&gt;&lt;li&gt;Module Metadata&lt;/li&gt;&lt;li&gt;Initialization and Cleanup Functions - Entry and Exit Points&lt;/li&gt;&lt;/ul&gt;&lt;h3&gt;License Identifier&lt;/h3&gt;&lt;p&gt;The first line &lt;code&gt;// SPDX-License-Identifier: GPL-2.0&lt;/code&gt; indicates the
license associated with the source file. Although linux kernel is
primarily licensed under GPL, there are several drivers that have a
different free license such as &lt;code&gt;MIT&lt;/code&gt;, &lt;code&gt;BSD&lt;/code&gt; etc.
&lt;a href=&quot;https://spdx.dev/&quot;&gt;SPDX&lt;/a&gt; or &lt;code&gt;Software Package Data Exchange&lt;/code&gt; is a
freely available open standard that provides a clean and unambiguous way
(one line) to indicate the license associated with the source file. If
we didnt have the SPDX standard, the license for each of these source
files would look something like this :&lt;/p&gt;&lt;pre&gt;&lt;code&gt;/*
 * Copyright (C) 2025 Meow
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License...
 */&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;which is harder to read and can be ambiguous sometimes.&lt;/p&gt;&lt;h3&gt;Header File&lt;/h3&gt;&lt;p&gt;&lt;code&gt;#include &amp;lt;linux/module.h&amp;gt;&lt;/code&gt;&lt;/p&gt;&lt;p&gt;This header provides the necessary kernel API's and macros to create a
kernel module. &lt;code&gt;MODULE_DESCRIPTION&lt;/code&gt;, &lt;code&gt;MODULE_AUTHOR&lt;/code&gt; and
&lt;code&gt;MODULE_LICENSE&lt;/code&gt; and several other macros are defined within this header
file.&lt;/p&gt;&lt;h3&gt;Module Metadata&lt;/h3&gt;&lt;p&gt;The macros &lt;strong&gt;MODULE_DESCRIPTION&lt;/strong&gt;, &lt;strong&gt;MODULE_AUTHOR&lt;/strong&gt; and &lt;strong&gt;MODULE_LICENSE&lt;/strong&gt;
define metadata about the module. This metadata is then embedded into
the resulting &lt;code&gt;.ko&lt;/code&gt; file that can be read by tools like &lt;code&gt;modinfo&lt;/code&gt; or the
kernel module loader.&lt;/p&gt;&lt;p&gt;So lets have a look at what these macros distill down to ultimately.&lt;/p&gt;&lt;p&gt;Looking at the definition of &lt;code&gt;MODULE_DESCRIPTION&lt;/code&gt;, &lt;code&gt;MODULE_AUTHOR&lt;/code&gt; or
&lt;code&gt;MODULE_LICENSE&lt;/code&gt; we can see that all of these macros boil down to
&lt;code&gt;MODULE_INFO&lt;/code&gt;.&lt;/p&gt;&lt;pre&gt;&lt;code&gt;/* Generic info of form tag = &amp;quot;info&amp;quot; */
#define MODULE_INFO(tag, info) __MODULE_INFO(tag, tag, info)&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Here we can observe from the comment that the module info is represented
in the form of &lt;strong&gt;tag:value&lt;/strong&gt; pairs.&lt;/p&gt;&lt;pre&gt;&lt;code&gt;#define __MODULE_INFO(tag, name, info)                    \
    static const char __UNIQUE_ID(name)[]                 \
        __used __section(&amp;quot;.modinfo&amp;quot;) __aligned(1)         \
        = __MODULE_INFO_PREFIX __stringify(tag) &amp;quot;=&amp;quot; info&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Here &lt;strong&gt;UNIQUE_ID&lt;/strong&gt; ensures that the variable names never clash. Basically
it appends &lt;strong&gt;UNIQUE_ID&lt;/strong&gt; prefix to the variable and a unique number as the
suffix to the variable. This is necessary because, if we look at the
previous code snippet we can see that we pass &lt;code&gt;tag&lt;/code&gt; as the &lt;code&gt;name&lt;/code&gt;
parameter to the macro. Therefore if invoke the macro multiple times
(like multiple authors), then it could result in variable name collision
which can be avoided using this.&lt;/p&gt;&lt;p&gt;But the variable name is not important here. Whats important is that the
data of this variable is added into &lt;code&gt;.modinfo&lt;/code&gt; section and the data
itself is &lt;code&gt;tag=info&lt;/code&gt;. Now modinfo section is very important as it
contains the module information.&lt;/p&gt;&lt;p&gt;In case of our hello world module, if we generate the LLVM IR for this
module, we can see that this is generated.&lt;/p&gt;&lt;p&gt;To generate the IR for this kernel module what I did is&lt;/p&gt;&lt;pre&gt;&lt;code&gt;make V=1 LLVM=1 M=custom_modules/hello_world&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;From this I extracted the line containing clang invocation and copied
that to a seperate bash script where i gave &lt;code&gt;emit-llvm -S&lt;/code&gt; option to
clang and specified it to generate &lt;code&gt;hello_world.ll&lt;/code&gt; file.&lt;/p&gt;&lt;pre&gt;&lt;code&gt;@__UNIQUE_ID_description481 = internal constant [40 x i8] c&amp;quot;description=A simple hello world module\00&amp;quot;, section &amp;quot;.modinfo&amp;quot;, align 1, !dbg !0
@__UNIQUE_ID_author482 = internal constant [26 x i8] c&amp;quot;author=Gopi Krishna Menon\00&amp;quot;, section &amp;quot;.modinfo&amp;quot;, align 1, !dbg !7
@__UNIQUE_ID_author483 = internal constant [12 x i8] c&amp;quot;author=Meow\00&amp;quot;, section &amp;quot;.modinfo&amp;quot;, align 1, !dbg !14
@__UNIQUE_ID_license484 = internal constant [12 x i8] c&amp;quot;license=GPL\00&amp;quot;, section &amp;quot;.modinfo&amp;quot;, align 1, !dbg !19&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;As we can observe, the data is stored in the form of tag:value pairs.
Also I added additional author to show you how &lt;strong&gt;UNIQUE_ID&lt;/strong&gt; is helping
here. Now if we look at the hexdump of &lt;code&gt;.modinfo&lt;/code&gt; section via readelf,
we can see that the data is stored in the same manner inside the
section:&lt;/p&gt;&lt;pre&gt;&lt;code&gt;readelf -x .modinfo custom_modules/hello_world/hello_world.k

Hex dump of section '.modinfo':
  0x00000000 64657363 72697074 696f6e3d 41207369 description=A si
  0x00000010 6d706c65 2068656c 6c6f2077 6f726c64 mple hello world
  0x00000020 206d6f64 756c6500 61757468 6f723d47  module.author=G
  0x00000030 6f706920 4b726973 686e6120 4d656e6f opi Krishna Meno
  0x00000040 6e006c69 63656e73 653d4750 4c006e61 n.license=GPL.na
  0x00000050 6d653d68 656c6c6f 5f776f72 6c640064 me=hello_world.d
  0x00000060 6570656e 64733d00 73726376 65727369 epends=.srcversi
  0x00000070 6f6e3d32 46374643 31393532 44453044 on=2F7FC1952DE0D
  0x00000080 44453443 30454638 45370076 65726d61 DE4C0EF8E7.verma
  0x00000090 6769633d 362e3136 2e30636c 616e672b gic=6.16.0clang+
  0x000000a0 20534d50 20707265 656d7074 206d6f64  SMP preempt mod
  0x000000b0 5f756e6c 6f616420 6d6f6476 65727369 _unload modversi
  0x000000c0 6f6e7320 00726574 706f6c69 6e653d59 ons .retpoline=Y
  0x000000d0 00&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Running modinfo, we can see the &lt;code&gt;.modinfo&lt;/code&gt; data&lt;/p&gt;&lt;pre&gt;&lt;code&gt;modinfo custom_modules/hello_world/hello_world.ko
filename:       /linux_work/linux-clang/custom_modules/hello_world/hello_world.ko
description:    A simple hello world module
author:         Gopi Krishna Menon
license:        GPL
name:           hello_world
depends:
srcversion:     2F7FC1952DE0DDE4C0EF8E7
vermagic:       6.16.0clang+ SMP preempt mod_unload modversions
retpoline:      Y&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt; : In the above code you can observe that there is vermagic, which
is also present in the &lt;code&gt;.modinfo&lt;/code&gt; section. Basically if you load a
module and &lt;strong&gt;vermagic&lt;/strong&gt; of module does not match whats there in the
kernel, it wont load the module. &lt;code&gt;=So modules built for one kernel is not compatible with other kernel.=&lt;/code&gt;&lt;/p&gt;&lt;pre&gt;&lt;code&gt;static int check_modinfo(struct module *mod, struct load_info *info, int flags)
{
    const char *modmagic = get_modinfo(info, &amp;quot;vermagic&amp;quot;);
    int err;

    if (flags &amp;amp; MODULE_INIT_IGNORE_VERMAGIC)
        modmagic = NULL;

    /* This is allowed: modprobe --force will invalidate it. */
    if (!modmagic) {
        err = try_to_force_load(mod, &amp;quot;bad vermagic&amp;quot;);
        if (err)
            return err;
    } else if (!same_magic(modmagic, vermagic, info-&amp;gt;index.vers)) {
        pr_err(&amp;quot;%s: version magic '%s' should be '%s'\n&amp;quot;,
               info-&amp;gt;name, modmagic, vermagic);
        return -ENOEXEC;
    }

    err = check_modinfo_livepatch(mod, info);
    if (err)
        return err;

    return 0;
}&lt;/code&gt;&lt;/pre&gt;&lt;h3&gt;Module License Enforcement&lt;/h3&gt;&lt;p&gt;The &lt;code&gt;MODULE_LICENCE&lt;/code&gt; macro is not just for display, it has runtime
implications. Basically - If you declare &lt;code&gt;MODULE_LICENCE(GPL)&lt;/code&gt;, the
module is treated as GPL compatible - If you declare
&lt;code&gt;MODULE_LICENCE(Proprietary)&lt;/code&gt; or leave blank, it is not GPL compatible
(meaning you cant access kernel symbols which are marked &lt;code&gt;GPL&lt;/code&gt; only
using &lt;code&gt;EXPORT_SYMBOL_GPL&lt;/code&gt;).&lt;/p&gt;&lt;p&gt;Whatever license we have supplied to this macro can impact what symbols
can we access from the kernel. So basically if we have used
&lt;code&gt;PROPRIETARY&lt;/code&gt; licence, then we cannot call or access any symbols from
the kernel which are marked &lt;code&gt;GPL&lt;/code&gt; only (using &lt;code&gt;EXPORT_SYMBOL&lt;/code&gt;).&lt;/p&gt;&lt;h3&gt;Initialization and Cleanup Functions&lt;/h3&gt;&lt;p&gt;The functions &lt;code&gt;hello_mod_init&lt;/code&gt; and &lt;code&gt;hello_mod_exit&lt;/code&gt; are initialization
and cleanup routines for the module.&lt;/p&gt;&lt;pre&gt;&lt;code&gt;static int __init hello_mod_init(void)
{
    pr_info(&amp;quot;%s: Hello World\n&amp;quot;, KBUILD_MODNAME);
    return 0;
}

static void __exit hello_mod_exit(void)
{
    pr_info(&amp;quot;%s: Unloading hello_mod\n&amp;quot;, KBUILD_MODNAME);
}&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;You can think of these as analogous to &lt;code&gt;setup&lt;/code&gt; and &lt;code&gt;teardown&lt;/code&gt;
functions. - &lt;strong&gt;hello_mod_init&lt;/strong&gt; is called when the module is inserted into
the kernel. It can be used for setting up resources required for this
perticular module - &lt;strong&gt;hello_mod_exit&lt;/strong&gt; is called when the module is
removed from the kernel. It can be used for cleaning up any resources
acquired during initialization.&lt;/p&gt;&lt;p&gt;Inside the init and exit function, I am simply printing &lt;em&gt;&amp;quot;Hello World&amp;quot;&lt;/em&gt;
and &lt;em&gt;&amp;quot;Unloading hello_mod&amp;quot;&lt;/em&gt; to the kernel ring buffer. Return value of 0
indicates success as usual. If the initialization fails for some reason,
you can also return the error code such as &lt;code&gt;-ENOMEM&lt;/code&gt;, &lt;code&gt;-EINVAL&lt;/code&gt; which
the kernel will handle accordingly.&lt;/p&gt;&lt;p&gt;The &lt;code&gt;__init&lt;/code&gt; and &lt;code&gt;__exit&lt;/code&gt; are annotations which instruct the compiler to
place these functions in special section &lt;code&gt;.init.text&lt;/code&gt; and &lt;code&gt;.exit.text&lt;/code&gt;.
The kernel can take this as a hint and can remove the code in these
sections when the initialisation or removal is complete. This can help
freeing up memory resources.&lt;/p&gt;&lt;p&gt;Finally the macros &lt;code&gt;module_init&lt;/code&gt; and &lt;code&gt;module_exit&lt;/code&gt; are used to register
these functions. &lt;code&gt;module_init&lt;/code&gt; basically specifies the driver
initialisation entry point. If the module is builtin (compiled into the
kernel), then it will be invoked during &lt;code&gt;do_initcalls()&lt;/code&gt;, otherwise it
will be invoked by &lt;code&gt;do_init_module&lt;/code&gt; during module loading&lt;/p&gt;&lt;pre&gt;&lt;code&gt;...
    freeinit-&amp;gt;init_text = mod-&amp;gt;mem[MOD_INIT_TEXT].base;
    freeinit-&amp;gt;init_data = mod-&amp;gt;mem[MOD_INIT_DATA].base;
    freeinit-&amp;gt;init_rodata = mod-&amp;gt;mem[MOD_INIT_RODATA].base;

    do_mod_ctors(mod);
    /* Start the module */
    if (mod-&amp;gt;init != NULL)
        ret = do_one_initcall(mod-&amp;gt;init); /* Here */
    if (ret &amp;lt; 0) {
        goto fail_free_freeinit;
    }
    if (ret &amp;gt; 0) {
        pr_warn(&amp;quot;%s: '%s'-&amp;gt;init suspiciously returned %d, it should &amp;quot;
            &amp;quot;follow 0/-E convention\n&amp;quot;
            &amp;quot;%s: loading module anyway...\n&amp;quot;,
            __func__, mod-&amp;gt;name, ret, __func__);
        dump_stack();
    }

    /* Now it's a first class citizen! */
    mod-&amp;gt;state = MODULE_STATE_LIVE;
    blocking_notifier_call_chain(&amp;amp;module_notify_list,
                     MODULE_STATE_LIVE, mod);


...&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;For exit, if it is not built into the kernel, it will be invoked by
&lt;code&gt;delete_module&lt;/code&gt; syscall which is invoked by &lt;code&gt;rmmod&lt;/code&gt;&lt;/p&gt;&lt;pre&gt;&lt;code&gt;...
    /* If it has an init func, it must have an exit func to unload */
    if (mod-&amp;gt;init &amp;amp;&amp;amp; !mod-&amp;gt;exit) {
        forced = try_force_unload(flags);
        if (!forced) {
            /* This module can't be removed */
            ret = -EBUSY;
            goto out;
        }
    }

    ret = try_stop_module(mod, flags, &amp;amp;forced);
    if (ret != 0)
        goto out;

    mutex_unlock(&amp;amp;module_mutex);
    /* Final destruction now no one is using it. */
    if (mod-&amp;gt;exit != NULL)
        mod-&amp;gt;exit(); /* HERE */
    blocking_notifier_call_chain(&amp;amp;module_notify_list,
                     MODULE_STATE_GOING, mod);
    klp_module_going(mod);
    ftrace_release_mod(mod);
...&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;So yea, this completes the dissection of a simple kernel module, in
future articles, I will talk about other macros such as &lt;code&gt;module_param&lt;/code&gt;,
&lt;code&gt;module_softdep&lt;/code&gt;, &lt;code&gt;module_weakdep&lt;/code&gt; etc.&lt;/p&gt;</content></entry></feed>