This shows you the differences between two versions of the page.
isc:labs:kernel:tasks:02 [2021/11/24 15:35] radu.mantu created |
— (current) | ||
---|---|---|---|
Line 1: | Line 1: | ||
- | ==== 02. [??p] Kernel modules ==== | ||
- | Way back when, kernels used to be monolithic, meaning that adding new functionality required recompiling and installing it, followed by a reboot. Today, things are much easier. By using the **kmod** daemon (''man 8 kmod''), users are allowed to load and unload __modules__ (i.e.: kernel object files) on demand, without all the fuss. These modules are C programs that must implement initialization and removal functions that are called automatically. Usually, these functions register / unregister other functions contained in your object with core kernel systems. | ||
- | |||
- | We can use **lsmod** to get a list of all present modules, and **modinfo** to obtain detailed information about a specific module. | ||
- | |||
- | <code bash> | ||
- | $ lsmod | ||
- | ecdh_generic 16384 1 bluetooth | ||
- | |||
- | $ modinfo ecdh_generic | grep description | ||
- | description: ECDH generic algorithm | ||
- | |||
- | $ modinfo bluetooth | grep description | ||
- | description: Bluetooth Core ver 2.22 | ||
- | </code> | ||
- | |||
- | What we can understand from this is that the [[https://elixir.bootlin.com/linux/latest/source/crypto/ecdh.c|Elliptic Curve Diffie-Hellman]] module is 16384 bytes in size and is used by one other module, via the [[https://elixir.bootlin.com/linux/latest/source/net/bluetooth/ecdh_helper.c|bluetooth ECDH helper]]. As you probably noticed, [[https://elixir.bootlin.com/linux/latest/source|elixir.bootlin.com]] is a critical resource in navigating the kernel code. | ||
- | |||
- | === [??p] Task A - Our first module === | ||
- | |||
- | Looking in the //%%skel/01/%%// directory from our code skeleton, we will find a minimal build environment for our first module. Alas, compiling a kernel module differs from compiling a user space program. But just slightly: kernel-specific headers must be used, user space-specific libraries (e.g.: **libc**) are generally unavailable (so no **printf()**) and lastly, the same options that were used to compile the kernel itself must be specified. To this end, the **kbuild** system was introduced. As you can see, our //Makefile// invokes its correpsondent from the kernel source directory in //%%/lib/modules/...%%//, which in turn uses the configuration in our //Kbuild// file. The **obj-m** variable specifies the name of the final output object file (in this case, //test.o//). **test-objs** contains a sequence of dependent object files, so if you split your code across multiple sources, just add them to **test-objs**. If you have a single source, you can drop **test-objs** but the **kbuild** system will expect a //test.c// file to be present. | ||
- | |||
- | Now, let's compile our module, upload it into the kernel, and see what happens: | ||
- | <code bash> | ||
- | $ make | ||
- | |||
- | $ sudo insmod test.ko | ||
- | $ sudo dmesg | ||
- | ... | ||
- | [ 6348.461247] my-first-module: Hello world! | ||
- | |||
- | $ sudo rmmod test | ||
- | $ sudo dmesg | ||
- | ... | ||
- | [ 6348.461247] my-first-module: Hello world! | ||
- | [ 6366.635090] my-first-module: Goodbye cruel, cruel world! | ||
- | </code> | ||
- | |||
- | Here, we used **insmod** to upload a //%%.ko%%// kernel object file into the kernel proper and **rmmod** to remove it. **dmesg** is a tool that prints the kernel message buffer. Note that there are multiple [[https://www.kernel.org/doc/html/latest/core-api/printk-basics.html|log levels]] ranging from **debug** to **emergency**. **pr_info()** is the kernel's **printf()** variant that corresponds to one of the less urgent levels. **dmesg** can be configured to squelch messages under a certain level but depending on how your kernel was compiled, some of the more important messages will also be echoed to your terminal. |