Linux Kernel Module Programming Guide
(sysprog21.github.io)- Linux Kernel Module Programming Guide Linux v5.10 या उससे नए versions पर loadable kernel modules बनाने के लिए एक मुफ्त guide है, जो development environment से लेकर build, load, debugging और प्रमुख kernel interfaces तक को एक ही flow में कवर करती है
- शुरुआती examples
hello-*.cके जरिएmodule_init(),module_exit(),kbuild,insmod,rmmod,dmesgसिखाते हैं, और QEMU-based devtools host system को नुकसान पहुंचने का जोखिम कम करते हैं - Kernel modules kernel address space में चलते हैं, इसलिए गलत pointer, unload order, concurrency, या user memory copy errors kernel memory corruption या system instability का कारण बन सकते हैं
- यह character devices,
/proc,seq_file, threaded IRQ, input, PCI, USB, block, network, Device Model, Device Tree, static key तक विस्तार करती है और registration/unregistration order व lifetime management को बार-बार समझाती है - Kernel internal APIs version के अनुसार बदलते हैं, इसलिए
LINUX_VERSION_CODE,KERNEL_VERSION,CONFIG_MODVERSIONS, SecureBoot signing, version magic जैसी conditions की जांच की जाती है, और examples में conditional compilation भी शामिल है
Guide की संरचना और basic flow
- यह guide GitHub repository और PDF document उपलब्ध कराने वाला kernel module learning material है, जिसे Open Software License 3.0 की शर्तों के तहत copy, modify और distribute किया जा सकता है
- मौजूदा guide Linux v5.10 को minimum supported baseline मानती है, और long-term support kernels में examples व instructions की compatibility बनाए रखना इसका लक्ष्य है
- Learners को C language और normal process programs लिखने का अनुभव चाहिए; kernel modules dynamically load/unload होते हैं और reboot किए बिना kernel functionality बढ़ाते हैं
- Basic development flow में kernel headers install करना,
makeसे.kobuild करना,modinfocheck करना,insmodसे load करना,dmesgयाjournalctl -kसे logs देखना, औरrmmodसे unload करना शामिल है devtools/kernel source और BusyBox root filesystem build करता है, QEMU में boot करता है,examples/को 9p virtfs से share करता है, और फिर guest में modules test करने देता है- Module initialization और cleanup के लिए
module_init()·module_exit()का उपयोग पसंद किया जाता है; पुरानेinit_module()·cleanup_module()तरीके x86 IBT enabled kernel 6.15 के बाद कुछ conditions में build failures पैदा कर सकते हैं - Kernel modules
printf()या libc का उपयोग नहीं करते; वे केवल kernel द्वारा exported symbols का उपयोग कर सकते हैं, और output terminal में नहीं बल्कि kernel log ring buffer में जाता है - User space और kernel space के बीच data movement के लिए
put_user,get_user,copy_to_user,copy_from_userजैसे dedicated functions जरूरी हैं - Character device example
register_chrdev,file_operations, dynamic major number,/devnode creation, exclusive open,put_user-based read, और unsupported write handling दिखाता है /procexampleproc_create,proc_ops, read/write callbacks,seq_fileAPI को कवर करता है, और Linux v5.6 के बाद/prochandlers मेंfile_operationsकी जगहproc_opsintroduce होने वाले बदलाव को reflect करता है- Threaded IRQ
request_threaded_irq()से top-half और bottom-half को अलग करता है; top-half interrupt context में केवल minimal work करता है औरIRQ_WAKE_THREADसे thread-based bottom-half को जगाता है - आगे के chapters input, PCI, USB, block, network, Device Model, Device Tree जैसे real driver areas तक फैलते हैं, और हर subsystem के registration method तथा userspace ABI selection पर केंद्रित रहते हैं
- Optimization और safety वाला हिस्सा
likely·unlikely, static key, छोटे kernel stack, FPU use न करने, uninitialized padding leaks, और double-underscore internal API usage में सावधानी को कवर करता है
Build और load करते समय सबसे पहले आने वाली constraints
- किसी एक kernel के लिए compile किया गया module दूसरे kernel में load नहीं हो सकता; version magic और
CONFIG_MODVERSIONSmatch न होने परInvalid module formatया symbol version mismatch होता है - अधिकांश सामान्य Linux distribution kernels में modversioning enabled हो सकती है, इसलिए अगर examples सीधे काम न करें तो modversioning disabled kernel या QEMU environment पर विचार करना चाहिए
- SecureBoot enabled systems में unsigned modules loading restricted हो सकती है, और यदि
Lockdown: insmod: unsigned module loading is restrictedदिखे तो SecureBoot disable करना या module signing process अपनाना जरूरी है
QEMU-based practice environment
devtools/setup.shkernel tarball और BusyBox download/build करता है और initramfs package करता हैdevtools/build-modules.shQEMU kernel target modules build करता है,devtools/boot.shguest shell देता है, औरdevtools/test-modules.shहर module के लिएinsmod·rmmodautomated tests चलाता है- GDB debugging के लिए
LKMPG_NO_PREBUILT=1 devtools/setup.shसेvmlinuxbuild करने के बादdevtools/boot.sh --gdbऔर remote GDB connection का उपयोग किया जाता है
Kernel code लिखने के नियम
- init function में registration/allocation fail हो सकते हैं, इसलिए acquired resources को
goto-based error paths में reverse order में release करना चाहिए - Kernel में callback structure register करने पर user space init return से पहले भी callback call कर सकता है, इसलिए internal initialization पूरा करने के बाद सबसे आखिर में register करना और cleanup में सबसे पहले unregister करना—यानी register last, unregister first rule—महत्वपूर्ण है
- process context, softirq/tasklet context, और hardirq context में sleep, user memory access,
GFP_KERNEL, mutex use की availability अलग-अलग होती है; इस distinction को गलत समझना common kernel bugs का कारण बनता है
Devices और subsystem-specific cautions
- Character devices driver को major number से identify करते हैं और driver के अंदर कई devices को minor number से अलग करते हैं; modern approach में
register_chrdev()की तुलना मेंcdevinterface recommended है - PCI driver fixed address assume नहीं करता, बल्कि PCI core द्वारा enumerated BAR resource को map करता है; Linux 5.10 के बाद के code में
pcim_enable_device()और device-managed resource API teardown bugs कम करने में उपयोगी हैं - USB driver को hotplug और disconnect को normal events की तरह handle करना चाहिए, और design में यह मानकर चलना चाहिए कि URB completion और disconnect, timeout, suspend, userspace shutdown आपस में race कर सकते हैं
- Block driver
blk-mq,request,gendisk, queue limit, flush/FUA semantics के आधार पर काम करता है, और simple read/write callback नहीं बल्कि asynchronous request completion model में भाग लेता है - Network driver
struct net_device,net_device_ops,sk_buff, NAPI, offload feature flag, link-state reporting से जुड़ा होता है; गलत offload declaration traffic corruption तक ले जा सकता है
Kernel version changes से निपटना
- Examples Linux 6.4 में
class_create()signature change, Linux v5.6 केproc_ops, Linux 6.11 मेंremove()return type change, और Linux 5.15~6.9 के बीचblk-mqhelper changes को conditional compilation से handle करते हैं - Kernel internal interfaces system calls की तुलना में ज्यादा बार बदलते हैं, इसलिए multiple kernels support करने वाले modules के लिए
LINUX_VERSION_CODEऔरKERNEL_VERSIONcomparisons से बचना मुश्किल है
Safety checkpoints
- Kernel stack user space stack से काफी छोटा होता है और कई systems में 8 KiB या 16 KiB के आसपास हो सकता है, इसलिए बड़े arrays के लिए
kmalloc()·kzalloc()का उपयोग करना चाहिए copy_to_user()से user space में data भेजते समय padding सहित हर byte initialized होना चाहिए; ऐसा न होने पर kernel memory information leak हो सकता है__kmalloc(),__list_add()जैसे double underscore से शुरू होने वाले APIs internal preconditions assume कर सकते हैं, इसलिए documentation जब तक न कहे, public wrapper को प्राथमिकता देनी चाहिए
छोड़ा गया scope
- Input processing के दौरान कुछ original chunks length/cost limits के कारण छोड़े गए बताए गए हैं, इसलिए यह summary guide के सभी chapters, examples और code paths को पूरी तरह cover नहीं करती
1 टिप्पणियां
Hacker News की रायें
QEMU kernel hacking का अनुभव लेने का अच्छा तरीका है
अच्छा होगा अगर कोई LDD(Linux Device Drivers) और Linux kernel की किताबों को अपडेट कर दे; ऐसी technical books से मुनाफा कमाना मुश्किल होता है, इसलिए Linux Foundation इसे sponsor करे तो भी अच्छा लगेगा
इसी हफ्ते v6.8 में यह issue QEMU + GDB से reproduce किया कि arm64 kernel command-line parameter 146 characters से ज्यादा होने पर kernel तुरंत चुपचाप रुक जाता है; फिर Debian 12 Bookworm amd64 host पर arm64 kernel build emulate करके problem code को line-by-line follow करते हुए root cause ढूंढा
flow यह है: build dependencies और cross-compile tools तैयार environment में arm64 kernel image और GDB के लिए script build करें, host पर
gdb, जरूरत हो तोgdb-multiarch, औरqemu-system-arminstall करें, फिरqemu-system-aarch64को-S -gdb tcp::1234के साथ stopped state में launch करें और दूसरे terminal सेgdb-multiarch ./vmlinuxके जरिए attach करेंइसके बाद GDB में
target remote :1234,break __parse_cmdline,continueचलाने पर memory, variables, stack inspect करने और single-step execution जैसी सामान्य GDB सुविधाएं इस्तेमाल की जा सकती हैंkernel GDB debugging और
lx-*scripts के लिए https://www.kernel.org/doc/html/latest/dev-tools/gdb-kernel-... देखेंGDB को
lx-*Python scripts इस्तेमाल कराने के लिए आम तौर परecho "add-auto-load-safe-path ${SRC_DIR}/scripts/gdb/vmlinux-gdb.py" > ~/.gdbinitजैसी path अनुमति भी जरूरी होती हैसंबंधित HN threads: https://news.ycombinator.com/item?id=35782630, https://news.ycombinator.com/item?id=28283030
The Linux Memory Manager भी देखने लायक है: https://linuxmemory.org/chapters
लेखक ने जुलाई की शुरुआत में जो last update भेजा था, उसके मुताबिक first draft पूरा हो गया था और अब publisher के साथ editing phase में प्रवेश कर गया है
कुछ examples सीधे चलाकर देखना मुश्किल लगते हैं
जैसे “Detecting button presses” मानता है कि आप RPi के लिए module build कर सकते हैं, लेकिन यह अपने-आप में cross-compilation जैसे काम मांगता है, इसलिए आसान नहीं हो सकता
detailed और hands-on है, और तुरंत kernel module build कराकर दिखाने वाला tutorial होने के कारण बेहतरीन है
साथ में देखने लायक resource: https://0xax.gitbooks.io/linux-insides/content/index.html
filesystem या memory management जैसी Linux kernel programming overall कहां से देखनी चाहिए, यह जानना चाहता हूं
बहुत पहले Robert Love की “Linux Kernel Development” थी, लेकिन लगता है अब वह update नहीं होती
इसे पहली बार पढ़े हुए करीब 22 साल हो गए :)