Introduce \src to generate Linux kernel source hyperlinks
The new command \src was introduced for preliminary hyperlink generation which points to Linux kernel source code. At present, stable/linux.git was referred: https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git We might switch to specific LTS kernels once requested.
This commit is contained in:
parent
da3dd34cd2
commit
2d368210ce
2
lib/kernelsrc.tex
Normal file
2
lib/kernelsrc.tex
Normal file
|
@ -0,0 +1,2 @@
|
|||
\newcommand*{\src}[2][]{\href{https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/tree/#2}%
|
||||
{\ifthenelse{\equal{#1}{}}{#2}{#1}}}
|
42
lkmpg.tex
42
lkmpg.tex
|
@ -5,6 +5,7 @@
|
|||
\usepackage{graphicx}
|
||||
\usepackage{fancyhdr}
|
||||
\usepackage{xparse}
|
||||
\usepackage{ifthen}
|
||||
|
||||
% tikz settings
|
||||
\usepackage{tikz}
|
||||
|
@ -33,6 +34,7 @@
|
|||
}
|
||||
|
||||
\input{lib/codeblock}
|
||||
\input{lib/kernelsrc}
|
||||
|
||||
\author{Peter Jay Salzman, Michael Burian, Ori Pomerantz, Bob Mottram, Jim Huang}
|
||||
\date{\today}
|
||||
|
@ -284,7 +286,7 @@ We needed to include \verb|<linux/kernel.h>| only for the macro expansion for th
|
|||
In the beginning there was \cpp|printk|, usually followed by a priority such as \cpp|KERN_INFO| or \cpp|KERN_DEBUG|.
|
||||
More recently this can also be expressed in abbreviated form using a set of print macros, such as \cpp|pr_info| and \cpp|pr_debug|.
|
||||
This just saves some mindless keyboard bashing and looks a bit neater.
|
||||
They can be found within \verb|include/linux/printk.h|.
|
||||
They can be found within \src{include/linux/printk.h}.
|
||||
Take time to read through the available priority macros.
|
||||
|
||||
\item About Compiling.
|
||||
|
@ -292,9 +294,9 @@ We needed to include \verb|<linux/kernel.h>| only for the macro expansion for th
|
|||
Former kernel versions required us to care much about these settings, which are usually stored in Makefiles.
|
||||
Although hierarchically organized, many redundant settings accumulated in sublevel Makefiles and made them large and rather difficult to maintain.
|
||||
Fortunately, there is a new way of doing these things, called kbuild, and the build process for external loadable modules is now fully integrated into the standard kernel build mechanism.
|
||||
To learn more on how to compile modules which are not part of the official kernel (such as all the examples you will find in this guide), see file \verb|Documentation/kbuild/modules.rst|.
|
||||
To learn more on how to compile modules which are not part of the official kernel (such as all the examples you will find in this guide), see file \src{Documentation/kbuild/modules.rst}.
|
||||
|
||||
Additional details about Makefiles for kernel modules are available in \verb|Documentation/kbuild/makefiles.rst|. Be sure to read this and the related files before starting to hack Makefiles. It will probably save you lots of work.
|
||||
Additional details about Makefiles for kernel modules are available in \src{Documentation/kbuild/makefiles.rst}. Be sure to read this and the related files before starting to hack Makefiles. It will probably save you lots of work.
|
||||
|
||||
\begin{quote}
|
||||
Here is another exercise for the reader.
|
||||
|
@ -307,7 +309,7 @@ What happens?
|
|||
\subsection{Hello and Goodbye}
|
||||
\label{hello_n_goodbye}
|
||||
In early kernel versions you had to use the \cpp|init_module| and \cpp|cleanup_module| functions, as in the first hello world example, but these days you can name those anything you want by using the \cpp|module_init| and \cpp|module_exit| macros.
|
||||
These macros are defined in \verb|include/linux/init.h|.
|
||||
These macros are defined in \src{include/linux/init.h}.
|
||||
The only requirement is that your init and cleanup functions must be defined before calling the those macros, otherwise you'll get compilation errors.
|
||||
Here is an example of this technique:
|
||||
|
||||
|
@ -326,7 +328,7 @@ clean:
|
|||
make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean
|
||||
\end{code}
|
||||
|
||||
Now have a look at \verb|drivers/char/Makefile| for a real world example.
|
||||
Now have a look at \src{drivers/char/Makefile} for a real world example.
|
||||
As you can see, some things get hardwired into the kernel (\verb|obj-y|) but where are all those \verb|obj-m| gone?
|
||||
Those familiar with shell scripts will easily be able to spot them.
|
||||
For those not, the \verb|obj-$(CONFIG_FOO)| entries you see everywhere expand into \verb|obj-y| or \verb|obj-m|, depending on whether the \verb|CONFIG_FOO| variable has been set to y or m.
|
||||
|
@ -344,7 +346,7 @@ There is also an \cpp|__initdata| which works similarly to \cpp|__init| but for
|
|||
The \cpp|__exit| macro causes the omission of the function when the module is built into the kernel, and like \cpp|__init|, has no effect for loadable modules.
|
||||
Again, if you consider when the cleanup function runs, this makes complete sense; built-in drivers do not need a cleanup function, while loadable modules do.
|
||||
|
||||
These macros are defined in \verb|include/linux/init.h| and serve to free up kernel memory.
|
||||
These macros are defined in \src{include/linux/init.h} and serve to free up kernel memory.
|
||||
When you boot your kernel and see something like Freeing unused kernel memory: 236k freed, this is precisely what the kernel is freeing.
|
||||
|
||||
\samplec{examples/hello-3.c}
|
||||
|
@ -361,7 +363,7 @@ module license 'unspecified' taints kernel.
|
|||
|
||||
You can use a few macros to indicate the license for your module.
|
||||
Some examples are "GPL", "GPL v2", "GPL and additional rights", "Dual BSD/GPL", "Dual MIT/GPL", "Dual MPL/GPL" and "Proprietary".
|
||||
They are defined within \verb|include/linux/module.h|.
|
||||
They are defined within \src{include/linux/module.h}.
|
||||
|
||||
To reference what license you're using a macro is available called \cpp|MODULE_LICENSE|.
|
||||
This and a few other macros describing the module are illustrated in the below example.
|
||||
|
@ -372,7 +374,7 @@ This and a few other macros describing the module are illustrated in the below e
|
|||
\label{modparam}
|
||||
Modules can take command line arguments, but not with the argc/argv you might be used to.
|
||||
|
||||
To allow arguments to be passed to your module, declare the variables that will take the values of the command line arguments as global and then use the \cpp|module_param()| macro, (defined in \verb|include/linux/moduleparam.h|) to set the mechanism up.
|
||||
To allow arguments to be passed to your module, declare the variables that will take the values of the command line arguments as global and then use the \cpp|module_param()| macro, (defined in \src{include/linux/moduleparam.h}) to set the mechanism up.
|
||||
At runtime, \sh|insmod| will fill the variables with any command line arguments that are given, like \sh|insmod ./mymodule.ko myvariable=5|.
|
||||
The variable declarations and macros should be placed at the beginning of the module for clarity.
|
||||
The example code should clear up my admittedly lousy explanation.
|
||||
|
@ -712,7 +714,7 @@ crw-rw---- 1 root dial 4, 66 Jul 5 2000 /dev/ttyS2
|
|||
crw-rw---- 1 root dial 4, 67 Jul 5 2000 /dev/ttyS3
|
||||
\end{verbatim}
|
||||
|
||||
If you want to see which major numbers have been assigned, you can look at \verb|Documentation/admin-guide/devices.txt|.
|
||||
If you want to see which major numbers have been assigned, you can look at \src{Documentation/admin-guide/devices.txt}.
|
||||
|
||||
When the system was installed, all of those device files were created by the \sh|mknod| command.
|
||||
To create a new char device named \verb|coffee| with major/minor number 12 and 2, simply do \sh|mknod /dev/coffee c 12 2|.
|
||||
|
@ -744,7 +746,7 @@ So just be aware that the word ``hardware'' in our discussion can mean something
|
|||
\label{sec:chardev}
|
||||
\subsection{The file\_operations Structure}
|
||||
\label{sec:file_operations}
|
||||
The \cpp|file_operations| structure is defined in \verb|include/linux/fs.h|, and holds pointers to functions defined by the driver that perform various operations on the device.
|
||||
The \cpp|file_operations| structure is defined in \src{include/linux/fs.h}, and holds pointers to functions defined by the driver that perform various operations on the device.
|
||||
Each field of the structure corresponds to the address of some function defined by the driver to handle a requested operation.
|
||||
|
||||
For example, every character driver needs to define a function that reads from the device.
|
||||
|
@ -831,7 +833,7 @@ Sin Linux v5.6, the \cpp|proc_ops| structure was introduced to replace the use o
|
|||
\subsection{The file structure}
|
||||
\label{sec:file_struct}
|
||||
|
||||
Each device is represented in the kernel by a file structure, which is defined in \verb|include/linux/fs.h|.
|
||||
Each device is represented in the kernel by a file structure, which is defined in \src{include/linux/fs.h}.
|
||||
Be aware that a file is a kernel level structure and never appears in a user space program.
|
||||
It is not the same thing as a \cpp|FILE|, which is defined by glibc and would never appear in a kernel space function.
|
||||
Also, its name is a bit misleading; it represents an abstract open `file', not a file on a disk, which is represented by a structure named inode.
|
||||
|
@ -864,7 +866,7 @@ A negative return value means the registration failed. Note that we didn't pass
|
|||
That is because the kernel doesn't care about the minor number; only our driver uses it.
|
||||
|
||||
Now the question is, how do you get a major number without hijacking one that's already in use?
|
||||
The easiest way would be to look through \verb|Documentation/admin-guide/devices.txt| and pick an unused one.
|
||||
The easiest way would be to look through \src{Documentation/admin-guide/devices.txt} and pick an unused one.
|
||||
That is a bad way of doing things because you will never be sure if the number you picked will be assigned later.
|
||||
The answer is that you can ask the kernel to assign you a dynamic major number.
|
||||
|
||||
|
@ -888,8 +890,8 @@ With \cpp|cleanup_module| that's impossible because it is a void function.
|
|||
However, there is a counter which keeps track of how many processes are using your module.
|
||||
You can see what its value is by looking at the 3rd field of \verb|/proc/modules|.
|
||||
If this number isn't zero, \sh|rmmod| will fail.
|
||||
Note that you do not have to check the counter from within \cpp|cleanup_module| because the check will be performed for you by the system call \cpp|sys_delete_module|, defined in \verb|include/linux/syscalls.h|.
|
||||
You should not use this counter directly, but there are functions defined in \verb|include/linux/module.h| which let you increase, decrease and display this counter:
|
||||
Note that you do not have to check the counter from within \cpp|cleanup_module| because the check will be performed for you by the system call \cpp|sys_delete_module|, defined in \src{include/linux/syscalls.h}.
|
||||
You should not use this counter directly, but there are functions defined in \src{include/linux/module.h} which let you increase, decrease and display this counter:
|
||||
|
||||
\begin{itemize}
|
||||
\item \cpp|try_module_get(THIS_MODULE)|: Increment the use count.
|
||||
|
@ -966,7 +968,7 @@ HelloWorld!
|
|||
|
||||
\subsection{The proc\_ops Structure}
|
||||
\label{sec:proc_ops}
|
||||
The \cpp|proc_ops| structure is defined in \verb|include/linux/proc_fs.h| in Linux v5.6+.
|
||||
The \cpp|proc_ops| structure is defined in \src{include/linux/proc\_fs.h} in Linux v5.6+.
|
||||
In older kernels, it used \cpp|file_operations| for custom hooks in \verb|/proc| file system, but it contains some members that are unnecessary in VFS, and every time VFS expands \cpp|file_operations| set, \verb|/proc| code comes bloated.
|
||||
On the other hand, not only the space, but also some operations were saved by this structure to improve its performance.
|
||||
For example, the file which never disappears in \verb|/proc| can set the \cpp|proc_flag| as \cpp|PROC_ENTRY_PERMANENT| to save 2 atomic ops, 1 allocation, 1 free in per open/read/close sequence.
|
||||
|
@ -1074,7 +1076,7 @@ If you want more information, you can read this web page:
|
|||
\item \url{https://kernelnewbies.org/Documents/SeqFileHowTo}
|
||||
\end{itemize}
|
||||
|
||||
You can also read the code of \verb|fs/seq_file.c| in the linux kernel.
|
||||
You can also read the code of \src{fs/seq\_file.c} in the linux kernel.
|
||||
|
||||
\section{sysfs: Interacting with your module}
|
||||
\label{sec:sysfs}
|
||||
|
@ -1148,7 +1150,7 @@ In the example below, the header file is chardev.h and the program which uses it
|
|||
|
||||
If you want to use ioctls in your own kernel modules, it is best to receive an official ioctl assignment, so if you accidentally get somebody else's ioctls, or if they get yours, you'll know something is wrong.
|
||||
% FIXME: use the right entry about ioctl assignment
|
||||
For more information, consult the kernel source tree at \verb|Documentation/driver-api/ioctl.rst|.
|
||||
For more information, consult the kernel source tree at \src{Documentation/driver-api/ioctl.rst}.
|
||||
|
||||
\samplec{examples/chardev2.c}
|
||||
|
||||
|
@ -1275,7 +1277,7 @@ In that case, we want to return with \cpp|-EINTR| immediately. This is important
|
|||
|
||||
There is one more point to remember. Some times processes don't want to sleep, they want either to get what they want immediately, or to be told it cannot be done.
|
||||
Such processes use the \cpp|O_NONBLOCK| flag when opening the file.
|
||||
The kernel is supposed to respond by returning with the error code \cpp|-EAGAIN| from operations which would otherwise block, such as opening the file in this example. The program \verb|cat_nonblock|, available in the \textit{examples/other} directory for this chapter, can be used to open a file with \cpp|O_NONBLOCK|.
|
||||
The kernel is supposed to respond by returning with the error code \cpp|-EAGAIN| from operations which would otherwise block, such as opening the file in this example. The program \sh|cat_nonblock|, available in the \verb|examples/other| directory, can be used to open a file with \cpp|O_NONBLOCK|.
|
||||
|
||||
\begin{verbatim}
|
||||
$ sudo insmod sleep.ko
|
||||
|
@ -1386,7 +1388,7 @@ The following source code illustrates a minimal kernel module which, when loaded
|
|||
If none of the examples in this chapter fit your debugging needs there might yet be some other tricks to try.
|
||||
Ever wondered what \cpp|CONFIG_LL_DEBUG| in make menuconfig is good for?
|
||||
If you activate that you get low level access to the serial port.
|
||||
While this might not sound very powerful by itself, you can patch \verb|kernel/printk.c| or any other essential syscall to print ASCII characters, thus makeing it possible to trace virtually everything what your code does over a serial line.
|
||||
While this might not sound very powerful by itself, you can patch \src{kernel/printk.c} or any other essential syscall to print ASCII characters, thus makeing it possible to trace virtually everything what your code does over a serial line.
|
||||
If you find yourself porting the kernel to some new and former unsupported architecture, this is usually amongst the first things that should be implemented.
|
||||
Logging over a netconsole might also be worth a try.
|
||||
|
||||
|
@ -1567,7 +1569,7 @@ You might need to do this for a short time and that is OK, but if you do not ena
|
|||
|
||||
\section{Where To Go From Here?}
|
||||
\label{sec:where_to_go}
|
||||
For people seriously interested in kernel programming, I recommend \href{https://kernelnewbies.org}{kernelnewbies.org} and the \verb|Documentation| subdirectory within the kernel source code which is not always easy to understand but can be a starting point for further investigation.
|
||||
For people seriously interested in kernel programming, I recommend \href{https://kernelnewbies.org}{kernelnewbies.org} and the \src{Documentation} subdirectory within the kernel source code which is not always easy to understand but can be a starting point for further investigation.
|
||||
Also, as Linus Torvalds said, the best way to learn the kernel is to read the source code yourself.
|
||||
|
||||
If you are interested in more examples of short kernel modules then searching on sites such as Github and Gitlab is a good way to start, although there is a lot of duplication of older LKMPG examples which may not compile with newer kernel versions.
|
||||
|
|
Loading…
Reference in New Issue
Block a user