<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
	<id>https://homeostasis.scs.carleton.ca/wiki/index.php?action=history&amp;feed=atom&amp;title=Operating_Systems_2019W%3A_Tutorial_6</id>
	<title>Operating Systems 2019W: Tutorial 6 - Revision history</title>
	<link rel="self" type="application/atom+xml" href="https://homeostasis.scs.carleton.ca/wiki/index.php?action=history&amp;feed=atom&amp;title=Operating_Systems_2019W%3A_Tutorial_6"/>
	<link rel="alternate" type="text/html" href="https://homeostasis.scs.carleton.ca/wiki/index.php?title=Operating_Systems_2019W:_Tutorial_6&amp;action=history"/>
	<updated>2026-04-05T16:59:34Z</updated>
	<subtitle>Revision history for this page on the wiki</subtitle>
	<generator>MediaWiki 1.42.1</generator>
	<entry>
		<id>https://homeostasis.scs.carleton.ca/wiki/index.php?title=Operating_Systems_2019W:_Tutorial_6&amp;diff=22224&amp;oldid=prev</id>
		<title>Soma: Created page with &quot;Again in this tutorial you will be building and installing kernel modules.  You will need root access to install kernel modules.  It is &#039;&#039;&#039;highly recommended&#039;&#039;&#039; that you use a...&quot;</title>
		<link rel="alternate" type="text/html" href="https://homeostasis.scs.carleton.ca/wiki/index.php?title=Operating_Systems_2019W:_Tutorial_6&amp;diff=22224&amp;oldid=prev"/>
		<updated>2019-03-07T20:58:36Z</updated>

		<summary type="html">&lt;p&gt;Created page with &amp;quot;Again in this tutorial you will be building and installing kernel modules.  You will need root access to install kernel modules.  It is &amp;#039;&amp;#039;&amp;#039;highly recommended&amp;#039;&amp;#039;&amp;#039; that you use a...&amp;quot;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;New page&lt;/b&gt;&lt;/p&gt;&lt;div&gt;Again in this tutorial you will be building and installing kernel modules.  You will need root access to install kernel modules.&lt;br /&gt;
&lt;br /&gt;
It is &amp;#039;&amp;#039;&amp;#039;highly recommended&amp;#039;&amp;#039;&amp;#039; that you use a comp3000 openstack instance for the exercises below for two reasons.  First, you may have difficulties compiling kernel modules on other systems.  Second, these operations are potentially dangerous and mistakes could &amp;#039;&amp;#039;&amp;#039;destroy all data&amp;#039;&amp;#039;&amp;#039; on the Linux system.  Consider yourself warned!&lt;br /&gt;
&lt;br /&gt;
In this tutorial you&amp;#039;ll be playing with the remember kernel module.  This module creates a device /dev/remember.  You can write data to this device and when you read from it, it will return the data that you most recently wrote.&lt;br /&gt;
&lt;br /&gt;
==Getting started==&lt;br /&gt;
&lt;br /&gt;
First, make sure your system is ready to build things.  On ubuntu:&lt;br /&gt;
&lt;br /&gt;
  sudo apt install build-essential libelf-dev&lt;br /&gt;
  sudo apt clean&lt;br /&gt;
&lt;br /&gt;
Note that libelf-dev is a new addition.  (To update your system, run &amp;quot;sudo apt update; sudo apt dist-upgrade&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
Download and unzip [https://homeostasis.scs.carleton.ca/~soma/os-2018f/code/tut7/remember.zip remember.zip].  From the command line:&lt;br /&gt;
&lt;br /&gt;
  wget https://homeostasis.scs.carleton.ca/~soma/os-2018f/code/tut7/remember.zip&lt;br /&gt;
  unzip remember.zip&lt;br /&gt;
&lt;br /&gt;
Next, build the module and install it:&lt;br /&gt;
&lt;br /&gt;
  cd remember&lt;br /&gt;
  make&lt;br /&gt;
  sudo insmod remember.ko&lt;br /&gt;
&lt;br /&gt;
And then test the module:&lt;br /&gt;
&lt;br /&gt;
  echo &amp;quot;Hello world&amp;quot; &amp;gt; /dev/remember&lt;br /&gt;
  cat /dev/remember&lt;br /&gt;
&lt;br /&gt;
Be sure to check the kernel logs before and after.  You may even want to follow the logs as you play with the module.  To do this, run:&lt;br /&gt;
&lt;br /&gt;
  tail -f /var/log/kern.log&lt;br /&gt;
&lt;br /&gt;
You&amp;#039;ll want to do this in a separate window.&lt;br /&gt;
&lt;br /&gt;
==Tasks/Questions==&lt;br /&gt;
&lt;br /&gt;
A good resource is [https://learnlinuxconcepts.blogspot.com/2014/02/linux-memory-management.html this page] on Linux kernel memory management.&lt;br /&gt;
&lt;br /&gt;
# What can you do with the Makefile other than type &amp;quot;make&amp;quot;?&lt;br /&gt;
# How much data can you write to /dev/remember?  What determines the limit?  (Hint: try writing the contents of remember.c to /dev/remember)&lt;br /&gt;
# When is data being allocated?  When is it deallocated?&lt;br /&gt;
# How can you increase the amount of data that /dev/remember stores?  (Hint: what is saved_data_order for?)&lt;br /&gt;
# Does the kernel use virtual or physical addresses for its own data structures?&lt;br /&gt;
# How are we copying data to and from kernel space?  Is it the same way we did before?&lt;br /&gt;
# What was changed from newgetpid.c that allows the /dev/remember device to be written to?  What parts of the code had to be changed?  What had to be added?&lt;br /&gt;
&lt;br /&gt;
==Code==&lt;br /&gt;
&lt;br /&gt;
===remember.c===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot; line&amp;gt;&lt;br /&gt;
/* &lt;br /&gt;
  remember.c&lt;br /&gt;
&lt;br /&gt;
  remember module COMP 3000, Carleton University&lt;br /&gt;
  remembers what is written to it, returns in when read along with&lt;br /&gt;
  info about how it is stored&lt;br /&gt;
&lt;br /&gt;
  License: GPLv2 or later&lt;br /&gt;
  Author: Anil Somayaji&lt;br /&gt;
  November 3, 2018&lt;br /&gt;
&lt;br /&gt;
  device driver and module code derived from:&lt;br /&gt;
  https://appusajeev.wordpress.com/2011/06/18/writing-a-linux-character-device-driver/&lt;br /&gt;
  and&lt;br /&gt;
  http://pete.akeo.ie/2011/08/writing-linux-device-driver-for-kernels.html&lt;br /&gt;
*/&lt;br /&gt;
&lt;br /&gt;
#include &amp;lt;linux/module.h&amp;gt;&lt;br /&gt;
#include &amp;lt;linux/string.h&amp;gt;&lt;br /&gt;
#include &amp;lt;linux/fs.h&amp;gt;&lt;br /&gt;
#include &amp;lt;linux/device.h&amp;gt;&lt;br /&gt;
#include &amp;lt;linux/init.h&amp;gt;&lt;br /&gt;
#include &amp;lt;linux/kernel.h&amp;gt;&lt;br /&gt;
#include &amp;lt;linux/sched.h&amp;gt;&lt;br /&gt;
#include &amp;lt;linux/uaccess.h&amp;gt;&lt;br /&gt;
#include &amp;lt;linux/mm.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
#define DEVICE_NAME &amp;quot;remember&amp;quot;&lt;br /&gt;
#define CLASS_NAME &amp;quot;comp3000&amp;quot;&lt;br /&gt;
&lt;br /&gt;
static struct class* remember_class = NULL;&lt;br /&gt;
static struct device* remember_device = NULL;&lt;br /&gt;
static int remember_major;&lt;br /&gt;
&lt;br /&gt;
static struct page *saved_data_page = NULL;&lt;br /&gt;
static char *saved_data = NULL;&lt;br /&gt;
static unsigned long saved_data_len = 0;&lt;br /&gt;
static int saved_data_max = PAGE_SIZE;&lt;br /&gt;
static int saved_data_order = 0;&lt;br /&gt;
&lt;br /&gt;
static int remember_open(struct inode *the_inode, struct file *f)&lt;br /&gt;
{&lt;br /&gt;
        pr_info(&amp;quot;Remember: device opened\n&amp;quot;);&lt;br /&gt;
        return 0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
static ssize_t remember_read(struct file *f, char *buf, size_t len, loff_t *offset)&lt;br /&gt;
{&lt;br /&gt;
        unsigned long n;&lt;br /&gt;
        char *error_msg = &amp;quot;Buffer too small.&amp;quot;;&lt;br /&gt;
        &lt;br /&gt;
        pr_info(&amp;quot;Remember: read started\n&amp;quot;);&lt;br /&gt;
        &lt;br /&gt;
        if (*offset &amp;gt; 0) {&lt;br /&gt;
                pr_info(&amp;quot;Remember: read non-zero offset, aborting\n&amp;quot;);&lt;br /&gt;
                return 0;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (len &amp;lt; saved_data_len) {&lt;br /&gt;
                pr_info(&amp;quot;Remember: read short buffer\n&amp;quot;);&lt;br /&gt;
                n = strlen(error_msg) + 1;  // Include terminating null byte&lt;br /&gt;
                if (n &amp;gt; len) {&lt;br /&gt;
                        n = len;&lt;br /&gt;
                }&lt;br /&gt;
                copy_to_user(buf, error_msg, n);&lt;br /&gt;
                &lt;br /&gt;
                return n;&lt;br /&gt;
        } else {&lt;br /&gt;
                pr_info(&amp;quot;Remember: read returning data, %ld bytes\n&amp;quot;,&lt;br /&gt;
                        saved_data_len);&lt;br /&gt;
                copy_to_user(buf, saved_data, saved_data_len);&lt;br /&gt;
                *offset = saved_data_len;&lt;br /&gt;
&lt;br /&gt;
                return saved_data_len;&lt;br /&gt;
        }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void init_saved_data(void)&lt;br /&gt;
{&lt;br /&gt;
        pr_info(&amp;quot;Remember: allocating data page&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
        if (saved_data) {&lt;br /&gt;
                pr_err(&amp;quot;Remember: saved_data already initialized!&amp;quot;);&lt;br /&gt;
        } else {       &lt;br /&gt;
                saved_data_page = alloc_pages(GFP_KERNEL,&lt;br /&gt;
                                              saved_data_order);&lt;br /&gt;
                saved_data = (char *) page_address(saved_data_page);&lt;br /&gt;
                saved_data_len = 0;&lt;br /&gt;
&lt;br /&gt;
                pr_info(&amp;quot;saved_data at kernel virtual address %lx&amp;quot;,&lt;br /&gt;
                        (unsigned long) saved_data);&lt;br /&gt;
                pr_info(&amp;quot;saved_data_page page struct at address %lx&amp;quot;,&lt;br /&gt;
                        (unsigned long) saved_data_page);&lt;br /&gt;
        }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void free_saved_data(void)&lt;br /&gt;
{&lt;br /&gt;
        if (saved_data_page) {&lt;br /&gt;
                pr_info(&amp;quot;Remember: freeing old data page&amp;quot;);&lt;br /&gt;
                __free_pages(saved_data_page, saved_data_order);&lt;br /&gt;
                saved_data_page = NULL;&lt;br /&gt;
                saved_data = NULL;&lt;br /&gt;
                saved_data_len = 0;&lt;br /&gt;
        }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
static ssize_t remember_write(struct file *f, const char *buf, size_t len,&lt;br /&gt;
                           loff_t *offset)&lt;br /&gt;
{&lt;br /&gt;
        unsigned long result;&lt;br /&gt;
&lt;br /&gt;
        if (*offset &amp;gt; 0) {&lt;br /&gt;
                pr_info(&amp;quot;Remember: write nonzero offset, aborting&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
                return 0;&lt;br /&gt;
        }&lt;br /&gt;
        &lt;br /&gt;
        free_saved_data();&lt;br /&gt;
        init_saved_data();&lt;br /&gt;
        &lt;br /&gt;
        if (len &amp;gt; saved_data_max) {&lt;br /&gt;
                len = saved_data_max;&lt;br /&gt;
        }&lt;br /&gt;
        &lt;br /&gt;
        pr_info(&amp;quot;Remember: write saving data, %ld bytes&amp;quot;, len);&lt;br /&gt;
&lt;br /&gt;
        result = copy_from_user(saved_data, buf, len);&lt;br /&gt;
        saved_data_len = len;        &lt;br /&gt;
&lt;br /&gt;
        *offset = len;&lt;br /&gt;
        &lt;br /&gt;
        return len;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
static int remember_release(struct inode *the_inode, struct file *f)&lt;br /&gt;
{        &lt;br /&gt;
        pr_info(&amp;quot;Remember: device closed\n&amp;quot;);&lt;br /&gt;
        return 0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
static struct file_operations remember_fops = {&lt;br /&gt;
        .open = remember_open,&lt;br /&gt;
        .read = remember_read,&lt;br /&gt;
        .write = remember_write,&lt;br /&gt;
        .release = remember_release,&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
static char *remember_devnode(struct device *dev, umode_t *mode)&lt;br /&gt;
{&lt;br /&gt;
        if (mode)&lt;br /&gt;
	        *mode = 0666;&lt;br /&gt;
        return NULL;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
static int __init remember_init(void)&lt;br /&gt;
{&lt;br /&gt;
        int retval;&lt;br /&gt;
  &lt;br /&gt;
        remember_major = register_chrdev(0, DEVICE_NAME, &amp;amp;remember_fops);&lt;br /&gt;
        if (remember_major &amp;lt; 0) {&lt;br /&gt;
                pr_err(&amp;quot;failed to register device: error %d\n&amp;quot;, remember_major);&lt;br /&gt;
                retval = remember_major;&lt;br /&gt;
                goto failed_chrdevreg;&lt;br /&gt;
        }&lt;br /&gt;
 &lt;br /&gt;
        remember_class = class_create(THIS_MODULE, CLASS_NAME);&lt;br /&gt;
        if (IS_ERR(remember_class)) {&lt;br /&gt;
                pr_err(&amp;quot;Remember: failed to register device class &amp;#039;%s&amp;#039;\n&amp;quot;,&lt;br /&gt;
                       CLASS_NAME);&lt;br /&gt;
                retval = PTR_ERR(remember_class);&lt;br /&gt;
                goto failed_classreg;&lt;br /&gt;
        }&lt;br /&gt;
 &lt;br /&gt;
        remember_class-&amp;gt;devnode = remember_devnode;&lt;br /&gt;
&lt;br /&gt;
        remember_device = device_create(remember_class, NULL,&lt;br /&gt;
                                        MKDEV(remember_major, 0),&lt;br /&gt;
                                        NULL, DEVICE_NAME);&lt;br /&gt;
&lt;br /&gt;
        if (IS_ERR(remember_device)) {&lt;br /&gt;
                pr_err(&amp;quot;Remember: failed to create device &amp;#039;%s&amp;#039;\n&amp;quot;, DEVICE_NAME);&lt;br /&gt;
                retval = PTR_ERR(remember_device);&lt;br /&gt;
                goto failed_devreg;&lt;br /&gt;
        }&lt;br /&gt;
        &lt;br /&gt;
        pr_info(&amp;quot;Remember: device registered using major %d.\n&amp;quot;,&lt;br /&gt;
                remember_major);&lt;br /&gt;
        &lt;br /&gt;
        return 0;&lt;br /&gt;
        &lt;br /&gt;
 failed_devreg:&lt;br /&gt;
        class_unregister(remember_class);&lt;br /&gt;
        class_destroy(remember_class);&lt;br /&gt;
 failed_classreg:&lt;br /&gt;
        unregister_chrdev(remember_major, DEVICE_NAME);&lt;br /&gt;
 failed_chrdevreg:&lt;br /&gt;
        return -1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
static void __exit remember_exit(void)&lt;br /&gt;
{&lt;br /&gt;
        free_saved_data();&lt;br /&gt;
&lt;br /&gt;
        device_destroy(remember_class, MKDEV(remember_major, 0));&lt;br /&gt;
        class_unregister(remember_class);&lt;br /&gt;
        class_destroy(remember_class);&lt;br /&gt;
        unregister_chrdev(remember_major, &amp;quot;remember&amp;quot;);&lt;br /&gt;
        pr_info(&amp;quot;Unloading Remember module.\n&amp;quot;);&lt;br /&gt;
        return;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
module_init(remember_init);&lt;br /&gt;
module_exit(remember_exit);&lt;br /&gt;
&lt;br /&gt;
MODULE_LICENSE(&amp;quot;GPL&amp;quot;);&lt;br /&gt;
MODULE_AUTHOR(&amp;quot;Anil Somayaji &amp;lt;soma@scs.carleton.ca&amp;gt;&amp;quot;);&lt;br /&gt;
MODULE_DESCRIPTION(&amp;quot;A remember character device module&amp;quot;);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Makefile===&lt;br /&gt;
&lt;br /&gt;
Note that the large spaces below should be tabs.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;make&amp;quot; line&amp;gt;&lt;br /&gt;
MODNAME := remember&lt;br /&gt;
obj-m := $(MODNAME).o&lt;br /&gt;
KDIR := /lib/modules/$(shell uname -r)/build&lt;br /&gt;
PWD := $(shell pwd)&lt;br /&gt;
default:&lt;br /&gt;
        $(MAKE) -C $(KDIR) SUBDIRS=$(PWD) modules&lt;br /&gt;
&lt;br /&gt;
clean:&lt;br /&gt;
        /bin/rm -f *.o *.ko *~&lt;br /&gt;
        /bin/rm -f Module.symvers modules.order Modules.symvers *.mod.c&lt;br /&gt;
        /bin/rm -f .*o.cmd .cache.mk&lt;br /&gt;
        /bin/rm -rf .tmp_versions&lt;br /&gt;
&lt;br /&gt;
zip:&lt;br /&gt;
        rm -f $(MODNAME).zip&lt;br /&gt;
        mkdir $(MODNAME)&lt;br /&gt;
        cp -a Makefile $(MODNAME).c $(MODNAME)&lt;br /&gt;
        zip -r $(MODNAME).zip $(MODNAME)&lt;br /&gt;
        rm -rf $(MODNAME)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;/div&gt;</summary>
		<author><name>Soma</name></author>
	</entry>
</feed>