CSE791 IoT: Notes for Mar 27, 2020

Why are we stuyding Linux drivers?

Resources

Three types of devices in Linux:

LDD3 Fig. 1-1: A split view of the kernel

Kernel programming

A “correct” kernel build file

ifneq ($(KERNELRELEASE),)
  obj-m := hello.o
else
  KERNELDIR ?= /lib/modules/$(shell uname -r)/build
  PWD := $(shell pwd)

default:
  $(MAKE) -C $(KERNELDIR) M=$(PWD) modules

endif

A kernel module example

#include <linux/init.h>
#include <linux/module.h>
MODULE_LICENSE("Dual BSD/GPL");

static int hello_int(void){
  printk(KERN_ALERT "Hello\n");
}

static void hello_exit(void){
  printk(KERN_ALERT "Goodbye\n");
}

static void module_function(void){
  // ...
}

module_init("hello_init");
module_exit("hello_exit");

Metadata

A kernel module usually contains some descriptive metadata. We can show the metadata of a kernel module using modinfo.

Showing kernel module metadata:

(base) user@machine:~$ modinfo /lib/modules/4.15.0-88-generic/kernel/drivers/acpi/video.ko
filename:       /lib/modules/4.15.0-88-generic/kernel/drivers/acpi/video.ko
license:        GPL
description:    ACPI Video Driver
author:         Bruno Ducrot
srcversion:     1E58EF1A1E4284895F3AF07
alias:          acpi*:LNXVIDEO:*
depends:        
retpoline:      Y
intree:         Y
name:           video
vermagic:       4.15.0-88-generic SMP mod_unload
signat:         PKCS#7
signer:         
sig_key:        
sig_hashalgo:   md4
parm:           brightness_switch_enabled:bool
parm:           allow_duplicates:bool
parm:           disable_backlight_sysfs_if:int
parm:           report_key_events:0: none, 1: output changes, 2: brightness changes, 3: all (int)
parm:           hw_changes_brightness:Set this to 1 on buggy hw which changes the brightness itself when a hotkey is pressed: -1: auto, 0: normal 1: hw-changes-brightness (int)
parm:           device_id_scheme:bool
parm:           only_lcd:int

A well-known one is MODULE_LICENSE. If MODULE_LICENSE is not called with a open source license, the kernel module will be considered proprietary. This would put restrictions on the kernel module.

Kernel symbol table

The table contains global kernel items—functions and variables—that are needed to implement modularized drivers. The public symbol table can be read in text form from the file /proc/kallsyms.

(base) user@machine:/proc$ sudo more /proc/kallsyms
0000000000000000 A irq_stack_union
0000000000000000 A __per_cpu_start
0000000000004000 A cpu_debug_store
0000000000005000 A cpu_tss_rw
0000000000008000 A gdt_page
0000000000009000 A exception_stacks
000000000000e000 A entry_stack_storage
000000000000f000 A espfix_waddr
000000000000f008 A espfix_stack
000000000000f010 A cpu_llc_id

A kernel module can put new symbols into the symbol table with EXPORT_SYMBOL or EXPORT_SYMBOL_GPL. the latter call will make the symbol visible to GPL-licensed modules only.

EXPORT_SYMBOL(name);
EXPORT_SYMBOL_GPL(name);

Once a symbol is put into the table, it is available across all kernel modules. For example, if the kernel module is a USB driver, it will add an entry for read_usb function into the symbol table for other drivers to use.

Loading a kernel module

LDD3 Fig. 2-1: Linking a module to the kernel

Difference between network interface and char/block device

Analyzing loopback.c

loopback.c