Difference Between Linux Loadable and Built-In Modules

Difference between Linux Loadable and built-in modules

Linux kernel supports inserting of modules (aka device drivers) in two ways:

  1. Built-in kernel modules - When the kernel is booted up, the kernel automatically inserts this driver in to the kernel (it's more like it is already part of the kernel code).
  2. Loadable kernel module (LKM) - A driver that is not automatically loaded by the kernel, the user can insert this module at run-time by insmod driver.ko or modprobe driver.ko

The advantage the loadable modules have over the built-in modules is that you can load unload them on run-time. This is good if you are working on a module and you need to test it. Every time you test it and you need to make changes to it, you can easily unload it (rmmod driver.ko or modprobe -r driver.ko) and then after making changes, you can insert it back. But for the built-in modules if you need to make any changes in the module then you need to compile the whole kernel and then reboot the system with the new image of the kernel.

Configuration:
You can configure a module to be either of the two by editing the .config file in the root folder of your kernel source:

DRIVER_1=y // y indicate a builtin module
DRIVER_1=m //m inicates a loadable module

Note: lsmod displays only the dynamically loaded modules not the built-in ones.

Read on: http://www.tldp.org/HOWTO/Module-HOWTO/x73.html

What is the difference for linux kernel :module or built-in?

If something is compiled in the linux kernel it will be part of the binary forever. So, it wont be loaded into the kernel on a "as-needed" basis. So, for example assume you have a realtek ethernet card on your machine why do you need drivers for intel ethernet cards?

One other thing, kernel modules in general can not reference a function in the kernel unless it is exported to modules using EXPORT_SYMBOL and its variants. So, if your driver need to reference functions from the kernel sources (which should not be the case anyways) then you have to add your driver into the kernel source tree.

Are builtin driver always prioritized over loadable modules?

I found the answer in the meanwhile and I documented it here:
http://0x0001.de/linux-driver-loading-registration-and-binding

To make a long story short:
Yes, builtin drivers are in general prioritized over loadable drivers.
Just because they are registered first and "first comes first serves" principle while binding.

Replace kernel builtin module with a loadable one

What I don't understand is why the platform device is not beeing found when the device-tree hasn't been changed except for status field value.

You seem to misunderstand what the status = "disable" attribute actually means.

Besides it meaning that the kernel should "not having it inserted at boot", a disabled node means that the device is not part of the current hardware configuration at all.

The driver, whether built-in or loadable module, is simply not to be probed because it has been disabled for the current configuration.

If you want your driver, whether built-in or loadable module, to be in the current configuration, then have a status = "okay" attribute in its Device Tree node.

IOW the Device Tree is for describing the current hardware configuration to the kernel.

Do not try to use the Device Tree to control loadable modules (since it cannot).

Here I'm in the situation where the module is loaded at boot by kernel as it's builtin and it appears into the device tree.

This statement makes no sense, as you seem to be describing your driver simultaneously as a built-in module as well as a loadable module.

A built-in driver does not have to be "loaded" in order to invoke its probe routine.

Because a driver can be either built-in or loadable, "loading" and "probing" are two distinct phases, and should not be conflated.

So I would like to keep the driver's code integrated into linux kernel but not having it inserted at boot.

You seem to be conflating the concept of the Linux kernel with the source code tree.

"Driver's code integrated into linux kernel" would typically be interpreted to mean a built-in driver, that is the driver is linked in and part of the kernel image that is loaded at boot.

Whereas driver code that is stored in the kernel source tree confers no designation has to whether it is a built-in or a loadable module. Many drivers (and other types of modules) can be built as either, and it is the build configuration that specifies which.

If you want your driver to be a loadable module, then (instead of changing the Device Tree):

a. you need to code your driver as a proper module;

b. you need to modify the Kconfig file to choose between a built-in or loadable module (i.e. a tristate versus bool selection specification).

c. configure the kernel to build your driver as a loadable module.


A device driver that is a loadable module and defined in the Device Tree could still be automatically loaded and probed during boot.
You may have to use module blacklisting to prevent that.


** ADDENDUM **

How to replace a builtin module with a loadable one without recompiling kernel to disable the builtin module?

You can't. That's why Kconfig forces you to choose between a loadable module (m) or built-in (y) if you want that driver to be built.

... then, once everything has been done, add those modifications to the builtin moduleusing a patch.

This makes no sense, since you only need a single copy of the driver source to build either a loadable module or a built-in version of the driver.

With this way of working I can just rebuild the .ko and insert it on my target platform instead of recompiling a kernel for each modification.

Seems like how you integrated your driver into the kernel source is questionable.

What have you actually done to integrate your driver into the kernel source tree?

Which Kconfig and Makefile did you modify for your driver?

What new CONFIG_* symbol(s) did you create for your driver?

Yes, you have to "recompile for each modification", but make is smart enough to rebuild only what is necessary. You could further shorten the kernel rebuild time by using make modules when you know that only your loadable driver has been modified.


TO CONCLUDE

  • It's not possible to use out-of-tree loadable module without recompiling the kernel to disable the builtin one.

BUT

  • Recompiling kernel only once with tristate at M and blacklisting the module on kernel boot line succeed.
  • Recompiling kernel only once with tristate at n succeed.

So the kernel has to be recompiled at least once, but then it's possible to work with an out-of-tree driver compiled as loadable module without having to remove the code integrated into linux sources.

What is the Linux built-in driver load order?

Built-in drivers wont be loaded, hence built-in. Their initialization functions are called and the drivers are activated when kernel sets up itself. These init functions are called in init/main.c::do_initcalls(). All init calls are classified in levels, which are defined in initcall_levels and include/linux/init.h

These levels are actuall symbols defined in linker script (arch/*/kernel/vmlinux.lds.*). At kernel compile time, the linker collects all function marked module_init() or other *_initcall(), classify in levels, put all functions in the same level together in the same place, and create like an array of function pointers.

What do_initcall_level() does in the run-time is to call each function pointed by the pointers in the array. There is no calling policy, except levels, in do_initcall_level, but the order in the array is decided in the link time.

So, now you can see that the driver's initiation order is fixed at the link time, but what can you do?

  1. put your init function in the higher level, or
  2. put your device driver at the higher position in Makefile

The first one is clear if you've read the above. ie) use early_initcall() instead if it is appropriate.

The second one needs a bit more explanation. The reason why the order in a Makefile matter is how the current kernel build system works and how the linkers works. To make a long story short, the build system takes all object files in obj-y and link them together. It is highly environment dependent but there is high probability that the linker place first object file in the obj-y in lower address, thus, called earlier.

If you just want your driver to be called earlier than other drivers in the same directory, this is simplest way to do it.

Step to build a built in kernel module?

I believe your question is similar to the question Compiling a driver as a part of a kernel, not as a module

The answer to that question mentioned modifying the kernel Makefiles to include your module object or directory.

In summary the steps are:

  1. Copy your driver source code directory under <linux kernel
    src>/drivers
    .
  2. Edit the Makefile to add the line:

    obj-y += your_driver_dir

  3. Edit the Makefile in your driver directory to add the line:

    obj-y := your_driver.o



Related Topics



Leave a reply



Submit