There was a big book with plain red leather covers; its tall pages were now almost filled. At the beginning there were many leaves covered with Bilbo's thin wandering hand; but most of it was written in Frodo's firm flowing script. It was divided into chapters but Chapter 80 was unfinished, and after that were some blank leaves.
"Why, you have nearly finished it, Mr. Frodo!" Sam exclaimed. "Well, you have kept at it, I must say."
"I have quite finished, Sam," said Frodo. "The last pages are for you."
—The Return of the King, Book VI, Chapter 9
In this studio, you will:
Please complete the required exercises below, as well as any optional enrichment exercises that you wish to complete. We encourage you to please work in groups of 2 or 3 people on each studio (and the groups are allowed to change from studio to studio) though if you would prefer to complete any studio by yourself that is allowed.
As you work through these exercises, please record your answers, and when finished upload them along with the relevant source code to the appropriate spot on Canvas. If you work in a group with other people, only one of you should please upload the answers (and any other files requested) for the studio, and if you need to resubmit (e.g., if a studio were to be marked incomplete when we grade it) the same person who submitted the studio originally should please do that.
Make sure that the name of each person who worked on these exercises is listed in the first answer, and make sure you number each of your responses so it is easy to match your responses with each exercise.
As the answer to the first exercise, list the names of the people who worked together on this studio.
On the Linux Lab cluster, please
create a new directory to hold your kernel modules,
e.g. /project/scratch01/compile/your-username/modules
and cd
into it. Save a copy of simple_module.c
(a simple
template for writing kernel modules in this course, based on the "Hello,
World!" module shown on pages 338 and 339 of Robert Love's Linux Kernel
Development, Third Edition) into that directory. In that directory also
create a Makefile that contains the line
obj-m := simple_module.o
and save that file. You should then build the module by issuing the commands
module add arm-rpi
LINUX_SOURCE=path to your Linux kernel source code
(note that the path above should end in something like linux_source/linux
)
and finally compile via
make -C $LINUX_SOURCE ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- M=$PWD modules
which if successful should produce a kernel module file named simple_module.ko
As the answer to this exercise, show the output that was produced by
make
.
sftp
to get the simple_module.ko
file you produced in the previous exercise.
First, clear out the contents of the system log using the command
sudo dmesg --clear
and then use the insmod
utility to load your kernel module into the
kernel, as in:
sudo insmod simple_module.ko
If you recieved no error messages, then your module has been
successfully loaded. To confirm this, you can check the system log by issuing
the command
dmesg
which prints out the system log, which now should show the message that
was printed when the module loaded. As the answer to this exercise,
please show the message that appears in the system log.
lsmod
lsmod
.
rmmod
. When using this tool you can either specify the module name
(as shown in lsmod
) or you can specify a .ko
file,
as insudo rmmod simple_module.ko
Remove your module now, and verify its removal as before. As the answer to
this exercise, copy the output of lsmod
and the line of the system log,
which show that the module was unloaded.
One kernel variable we will talk about this semester is the jiffies
counter. This variable keeps track of how many timer interrupts
(also called ticks) have occured since system boot.
You will learn more about jiffies and timer interrupts in an upcoming class.
Copy simple_module.c
to a new file called jiffies_module.c
and modify that new file, so that the system log messages that are generated when the module
is loaded and unloaded also give the value of the jiffies
variable
(hint: it's an unsigned long
) to the system log.
Note that although this jiffies
variable is not readily available
to userspace programs, it is available directly when in kernelspace.
Update your Makefile
, build your new kernel module and use
sftp
to copy the jiffies_module.ko
file that was
produced for it, over to your Raspberry Pi.
On your Raspberry Pi, load and unload your new kernel module, and as the
answer to this exercise please copy and paste the system log message that shows
the values of the jiffies
variable when your module was loaded and
when it was unloaded, and say how many ticks occurred between those messages.
Please submit
jiffies_module.c
file for the new kernel module you created.
/include/uapi/asm-generic/errno-base.h
. Modify
your init function to return positive and negative values, respectively.
As the answer to this exercise please describe briefly what happens when you
load the module, and what you see in the system logs because of that.
Kernel symbols that are available to be used in loadable modules
are called exported symbols and are identified by the
EXPORT_SYMBOL
macro. You can see a list of all kernel symbols
by looking at the file /proc/kallsyms, e.g. cat /proc/kallsyms
.
You might notice that this is very similar to the symbol table of a traditional
application. (Which you can print with the program nm
, if you've
never done that before. Try it on any binary!) In fact, their syntax is
identical, so you can use the command man 1 nm
to find some more information
about how to decode the contents of /proc/kallsyms
.
Symbols that have been exported can be found in this list with the prefixes
__kstrtab_
, and __ksymtab_
. These prefixes denote
a special kernel symbol that stores the name of the exported symbol and a
struct that stores information about the symbol, respectively. See the
definition of EXPORT_SYMBOL
to see how these are generated.
As the answer to this exercise, please list a few of those symbols that
are available for use in a kernel module.
The optional enrichment exercises in the Linux System Calls studio had you create a system call to retrieve a value directly from the Cycle Count Register (CCNT) on the Raspberry Pi's ARM CPU. Today, we will implement a kernel module to allow userspace programs to read the CCNT value without having to make a system call.
If you did not complete this enrichment exercise in the System Calls studio,
please download this driver file,
and place it in the arch/arm/include/asm
directory in your Linux kernel source tree.
Now, please download the kernel module code,
enable_ccnt.c,
into the kernel modules directory you created in Exercise 2.
Follow the instructions in Exercises 2 and 3 to compile the kernel module,
transfer it to your Raspberry Pi with sftp
,
and load it using insmod
.
To verify that it loaded correctly, issue the command:
dmesg | tail
You should see messages written to the kernel log indicating that the Cycle Counter has been enabled, and showing a current cycle count value.
Next, retrieve the same driver file
onto your Raspberry Pi, and create a program
that #include
s it.
Have the program call the function pmccntr_get()
,
which has the signature:
unsigned long long pmccntr_get(void)
In particular, call this function twice to return two cycle counts in a row. As the answer to this exercise, please say how many CPU cycles it takes to run this function. If you completed the enrichment exercise in the System Calls studio, compare this cycle duration to the number of cycles it took to make the system call.