I am entering my final step in the internship with the encoding almost finished (there are still some problems to consider and testing to be done, especially on machines with multiple CPUs). This article will be rather short as I am focusing on my coding now more.
I have used the library libqrencode after realizing that it was actually a LGPLv2.1 (I thought it was LGPLv3) and that kind of license can be transformed to a GPLv2. If it were a LGPLv3 it wouldn’t have been compatible with a GPLv2. So what I did was translate to kernel space and use most of it as it is.
As I left the license transformation for later on I put all my work on gitlab because on github I would have been posting publicly (I don’t have private repos as an option for github) a code without the proper licensing.
Oops in depth
What I learned as a general thing is that the best way to understand something is by reading documentation, reading the source code and testing it. These were the steps I followed. As I mentioned before, an Oops occurs when you’re doing something illegal like a ‘NULL pointer deference’. The kernel may or may not continue after an Oops occurs (or a panic for that matter).
How does it actually work? It is a rather simple mechanism in principle. An Oops has several information useful for debugging like call trace, stack trace, eip, etc. The kernel dumps information to the console about these using ‘printk’ calls. For example, I did an inspection of the x86 dumpstack file. The architecture dependent files are located in the arch folder with a folder for each one, so here’s the link on lxr.free-electrons.com: http://lxr.free-electrons.com/source/arch/x86/kernel/dumpstack.c
In order for the ‘printk’ to work on multiple CPUs is by using a lock for exclusive access to the console. All this is done in the printk.h in the architecture independent part of the kernel. The idea I had was to use a configuration option so that each printk call during an Oops has a lateral effect of writing into a pagesize (4K) static buffer. Then, after the Oops handling is over and the last printk call (it ends with a End of Call Trace string) is done, the buffer is encoded and written.
Another useful thing in the kernel is the configuration menu. Before compiling the kernel, you write the following command in your terminal
You then enter a UI that lets you choose several options for compiling the kernel. You can see debug information, driver options, certain security information and many more. You select to include on by pressing the space bar and by pressing Enter you may navigate a submenu. For some options you can select it and there appears a ‘*’ before that option, deselect it (you have a ‘-‘ before it) or insert it as a module ‘M’.
You can include your own option, as I did with my QR library option by adding information in the Kconfig file. So for example, right now my Kconfig file inside the lib/ directory (this is where the library folder is) has these following lines:
config QRLIB bool "QR encoding library" help QR encoding library
I can then use the CONFIG_QRLIB to test if this option has been enabled.
In order for the library to compile I had to write a Makefile inside the directory and then add a hook for it in the lib/ directory’s Makefile. The way the kernel builds is by having a sort of hierarchical Makefile (it is rather normal, if you think how all big projects are compiled, but the kernel has some additional scripts which is cool).
The next step is doing the compression. This is rather delicate, but I hope to come with a good solution. There are several solutions of compression already in the kernel. I will test these first.