[FE training-materials-updates] Improve kernel frameworks to introduce character drivers

Thomas Petazzoni thomas.petazzoni at free-electrons.com
Mon Sep 30 15:29:23 CEST 2013


Repository : git://git.free-electrons.com/training-materials.git

On branch  : kernel-ng
Link       : http://git.free-electrons.com/training-materials/commit/?id=2268bd9eba9ddfae98191c5a0ede3626b3daac50

>---------------------------------------------------------------

commit 2268bd9eba9ddfae98191c5a0ede3626b3daac50
Author: Thomas Petazzoni <thomas.petazzoni at free-electrons.com>
Date:   Mon Sep 30 15:27:25 2013 +0200

    Improve kernel frameworks to introduce character drivers
    
    We no longer detail the entire API to register raw character drivers,
    since we're showing how to use kernel frameworks (input and
    misc). However, to explain what a kernel framework is, what is an
    ioctl, we need to introduce a few details about character drivers.
    
    Therefore, this commit extends the "Kernel Frameworks" slides by
    starting with a introduction on character drivers, with many slides
    and diagrams borrowed from our previous presentation on this topic.
    
    Signed-off-by: Thomas Petazzoni <thomas.petazzoni at free-electrons.com>


>---------------------------------------------------------------

2268bd9eba9ddfae98191c5a0ede3626b3daac50
 ...kernel-driver-development-character-drivers.tex |  636 --------------------
 .../copy-to-from-user.dia                          |    0
 slides/kernel-frameworks/kernel-frameworks.tex     |  357 ++++++++++-
 .../user-kernel-exchanges.dia                      |    0
 4 files changed, 353 insertions(+), 640 deletions(-)

diff --git a/slides/kernel-driver-development-character-drivers/kernel-driver-development-character-drivers.tex b/slides/kernel-driver-development-character-drivers/kernel-driver-development-character-drivers.tex
deleted file mode 100644
index 7e8ffb4..0000000
--- a/slides/kernel-driver-development-character-drivers/kernel-driver-development-character-drivers.tex
+++ /dev/null
@@ -1,636 +0,0 @@
-\subsection{Character drivers}
-
-\begin{frame}
-  \frametitle{Usefulness of character drivers}
-  \begin{itemize}
-  \item Except for storage device drivers, most drivers for devices
-    with input and output flows are implemented as character drivers.
-  \item So, most drivers you will face will be character drivers.
-  \end{itemize}
-\end{frame}
-
-\begin{frame}
-  \frametitle{Creating a Character Driver 1/2}
-  \begin{itemize}
-  \item User-space needs
-    \begin{itemize}
-    \item The name of a device file in \code{/dev} to interact with
-      the device driver through regular file operations (open, read,
-      write, close...)
-    \end{itemize}
-  \item The kernel needs
-    \begin{itemize}
-    \item To know which driver is in charge of device files with a
-      given major / minor number pair
-    \item For a given driver, to have handlers (\emph{file
-        operations}) to execute when user-space opens, reads, writes
-      or closes the device file.
-    \end{itemize}
-  \end{itemize}
-\end{frame}
-
-
-\begin{frame}
-  \frametitle{Creating a Character Driver 2/2}
-  \begin{center}
-    \includegraphics[width=\textwidth]{slides/kernel-driver-development-character-drivers/user-kernel-exchanges.pdf}
-  \end{center}
-\end{frame}
-
-\begin{frame}
-  \frametitle{Implementing a character driver}
-  \begin{itemize}
-  \item Four major steps
-    \begin{itemize}
-    \item Implement operations corresponding to the system calls an
-      application can apply to a file: \emph{file operations}
-    \item Define a \code{file_operations} structure associating function
-      pointers to their implementation in your driver
-    \item Reserve a set of major and minors for your driver
-    \item Tell the kernel to associate the reserved major and minor to
-      your file operations
-    \end{itemize}
-  \item This is a very common design scheme in the Linux kernel
-    \begin{itemize}
-    \item A common kernel infrastructure defines a set of operations
-      to be implemented by a driver and functions to register your
-      driver
-    \item Your driver only needs to implement this set of well-defined
-      operations
-    \end{itemize}
-  \end{itemize}
-\end{frame}
-
-\begin{frame}
-  \frametitle{File operations 1/3}
-  \begin{itemize}
-  \item Before registering character devices, you have to define
-    \code{file_operations} (called \emph{fops}) for the device files.
-  \item The \code{file_operations} structure is generic to all files
-    handled by the Linux kernel. It contains many operations that
-    aren't needed for character drivers.
-  \end{itemize}
-\end{frame}
-
-\begin{frame}[fragile]
-  \frametitle{File operations 2/3}
-  \begin{itemize}
-  \item Here are the most important operations for a character
-    driver. All of them are optional.
-  \end{itemize}
-\begin{minted}{c}
-struct file_operations {
-    ssize_t (*read) (struct file *, char __user *,
-        size_t, loff_t *);
-    ssize_t (*write) (struct file *, const char __user *,
-        size_t, loff_t *);
-    long (*unlocked_ioctl) (struct file *, unsigned int,
-        unsigned long);
-    int (*mmap) (struct file *, struct vm_area_struct *);
-    int (*open) (struct inode *, struct file *);
-    int (*release) (struct inode *, struct file *);
-};
-\end{minted}
-\end{frame}
-
-\begin{frame}[fragile]
-  \frametitle{open() and release()}
-  \begin{itemize}
-  \item \mint{c}+int foo_open(struct inode *i, struct file *f)+
-    \begin{itemize}
-    \item Called when user-space opens the device file.
-    \item \code{inode} is a structure that uniquely represent a file
-      in the system (be it a regular file, a directory, a symbolic
-      link, a character or block device)
-    \item \code{file} is a structure created every time a file is
-      opened. Several file structures can point to the same
-      \code{inode} structure.
-      \begin{itemize}
-      \item Contains information like the current position, the
-        opening mode, etc.
-      \item Has a \code{void *private_data} pointer that one can
-        freely use.
-      \item A pointer to the file structure is passed to all other
-        operations
-      \end{itemize}
-    \end{itemize}
-  \item \mint{c}+int foo_release(struct inode *i, struct file *f)+
-    \begin{itemize}
-    \item Called when user-space closes the file.
-    \end{itemize}
-  \end{itemize}
-\end{frame}
-
-\begin{frame}
-  \frametitle{read()}
-  \begin{itemize}
-  \item \mint{c}+ssize_t foo_read(struct file *f, __user char *buf,+
-    \mint{c}+size_t sz, loff_t *off)+
-    \begin{itemize}
-    \item Called when user-space uses the \code{read()} system call on
-      the device.
-    \item Must read data from the device, write at most \code{sz}
-      bytes in the user-space buffer \code{buf}, and update the
-      current position in the file \code{off}. \code{f} is a pointer
-      to the same file structure that was passed in the \code{open()}
-      operation
-    \item Must return the number of bytes read.
-    \item On UNIX, \code{read()} operations typically block when there
-      isn't enough data to read from the device
-    \end{itemize}
-  \end{itemize}
-\end{frame}
-
-\begin{frame}[fragile]
-  \frametitle{write()}
-  \begin{itemize}
-  \item \mint{c}+ssize_t foo_write(struct file *f,+
-    \mint{c}+__user const char *buf, size_t sz, loff_t *off)+
-    \begin{itemize}
-    \item Called when user-space uses the \code{write()} system call
-      on the device
-    \item The opposite of \code{read}, must read at most \code{sz}
-      bytes from \code{buf}, write it to the device, update \code{off}
-      and return the number of bytes written.
-    \end{itemize}
-  \end{itemize}
-\end{frame}
-
-\begin{frame}
-  \frametitle{Exchanging data with user-space 1/3}
-  \begin{itemize}
-  \item Kernel code isn't allowed to directly access user-space
-    memory, using \code{memcpy} or direct pointer dereferencing
-    \begin{itemize}
-    \item Doing so does not work on some architectures
-    \item If the address passed by the application was invalid, the
-      application would segfault.
-    \end{itemize}
-  \item To keep the kernel code portable and have proper error
-    handling, your driver must use special kernel functions to
-    exchange data with user-space.
-  \end{itemize}
-\end{frame}
-
-\begin{frame}[fragile]
-  \frametitle{Exchanging data with user-space 2/3}
-  \begin{itemize}
-  \item A single value
-    \begin{itemize}
-    \item \code{get_user(v, p);}
-      \begin{itemize}
-      \item The kernel variable \code{v} gets the value pointed by the
-        user-space pointer \code{p}
-      \end{itemize}
-    \item \code{put_user(v, p);}
-      \begin{itemize}
-      \item The value pointed by the user-space pointer \code{p} is
-        set to the contents of the kernel variable \code{v}.
-      \end{itemize}
-    \end{itemize}
-  \item A buffer
-    \begin{itemize}
-    \item \mint{c}+unsigned long copy_to_user(void __user *to,+
-      \mint{c}+const void *from, unsigned long n);+
-    \item \mint{c}+unsigned long copy_from_user(void *to,+
-      \mint{c}+const void __user *from, unsigned long n);+
-    \end{itemize}
-  \item The return value must be checked. Zero on success, non-zero on
-    failure. If non-zero, the convention is to return -\code{EFAULT}.
-  \end{itemize}
-\end{frame}
-
-\begin{frame}
- \frametitle{Exchanging data with user-space 3/3}
- \begin{center}
-    \includegraphics[width=\textwidth]{slides/kernel-driver-development-character-drivers/copy-to-from-user.pdf}
- \end{center}
-\end{frame}
-
-\begin{frame}
-  \frametitle{Zero copy access to user memory}
-  \begin{itemize}
-  \item Having to copy data to our from an intermediate kernel buffer
-    is expensive.
-  \item \emph{Zero copy} options are possible:
-    \begin{itemize}
-    \item \code{mmap()} system call to allow user space to directly
-      access memory mapped I/O space (covered in the \code{mmap()}
-      section).
-    \item \code{get_user_pages()} to get a mapping to user pages
-      without having to copy them. See \url{http://j.mp/oPW6Fb}
-      (Kernel API doc). This API is more complex to use though.
-    \end{itemize}
-  \end{itemize}
-\end{frame}
-
-\begin{frame}[fragile]
-  \frametitle{Read Operation Example}
-\begin{minted}[fontsize=\tiny]{c}
-static ssize_t
-acme_read(struct file *file, char __user * buf, size_t count, loff_t * ppos)
-{
-        /* The acme_buf address corresponds to a device I/O memory area */
-        /* of size acme_bufsize, obtained with ioremap() */
-        int remaining_size, transfer_size;
-
-        remaining_size = acme_bufsize - (int)(*ppos);
-                                /* bytes left to transfer */
-        if (remaining_size == 0) {
-                                /* All read, returning 0 (End Of File) */
-                return 0;
-        }
-
-        /* Size of this transfer */
-        transfer_size = min_t(int, remaining_size, count);
-
-        if (copy_to_user
-            (buf /* to */ , acme_buf + *ppos /* from */ , transfer_size)) {
-                return -EFAULT;
-        } else {                /* Increase the position in the open file */
-                *ppos += transfer_size;
-                return transfer_size;
-        }
-}
-\end{minted}
-Piece of code available at \url{http://free-electrons.com/doc/c/acme.c}
-\end{frame}
-
-\begin{frame}[fragile]
-  \frametitle{Write Operation Example}
-\begin{minted}[fontsize=\tiny]{c}
-static ssize_t
-acme_write(struct file *file, const char __user *buf, size_t count,
-           loff_t *ppos)
-{
-        int remaining_bytes;
-
-        /* Number of bytes not written yet in the device */
-        remaining_bytes = acme_bufsize - (*ppos);
-
-        if (count > remaining_bytes) {
-                /* Can't write beyond the end of the device */
-                return -EIO;
-        }
-
-        if (copy_from_user(acme_buf + *ppos /*to*/ , buf /*from*/ , count)) {
-                return -EFAULT;
-        } else {
-                /* Increase the position in the open file */
-                *ppos += count;
-                return count;
-        }
-}
-\end{minted}
-Piece of code available at \url{http://free-electrons.com/doc/c/acme.c}
-\end{frame}
-
-
-\begin{frame}[fragile]
-  \frametitle{unlocked\_ioctl()}
-  \begin{itemize}
-  \item \mint{c}+long unlocked_ioctl(struct file *f,+
-    \mint{c}+unsigned int cmd, unsigned long arg)+
-    \begin{itemize}
-    \item Associated to the \code{ioctl()} system call.
-    \item Called unlocked because it didn't hold the Big Kernel Lock
-      (gone now).
-    \item Allows to extend the driver capabilities beyond the limited
-      read/write API.
-    \item For example: changing the speed of a serial port, setting
-      video output format, querying a device serial number...
-    \item \code{cmd} is a number identifying the operation to perform
-    \item \code{arg} is the optional argument passed as third argument
-      of the \code{ioctl()} system call. Can be an integer, an
-      address, etc.
-    \item The semantic of \code{cmd} and \code{arg} is
-      driver-specific.
-    \end{itemize}
-  \end{itemize}
-\end{frame}
-
-\begin{frame}[fragile]
-  \frametitle{ioctl() example: kernel side}
-\begin{minted}[fontsize=\tiny]{c}
-static long phantom_ioctl(struct file *file, unsigned int cmd,
-    unsigned long arg)
-{
-    struct phm_reg r;
-    void __user *argp = (void __user *)arg;
-
-    switch (cmd) {
-    case PHN_SET_REG:
-        if (copy_from_user(&r, argp, sizeof(r)))
-            return -EFAULT;
-        /* Do something */
-        break;
-    case PHN_GET_REG:
-        if (copy_to_user(argp, &r, sizeof(r)))
-            return -EFAULT;
-        /* Do something */
-        break;
-    default:
-        return -ENOTTY;
-    }
-
-    return 0; }
-\end{minted}
-Selected excerpt from \code{drivers/misc/phantom.c}
-\end{frame}
-
-\begin{frame}[fragile]
-  \frametitle{Ioctl() Example: Application Side}
-\begin{minted}{c}
-int main(void)
-{
-    int fd, ret;
-    struct phm_reg reg;
-
-    fd = open("/dev/phantom");
-    assert(fd > 0);
-
-    reg.field1 = 42;
-    reg.field2 = 67;
-
-    ret = ioctl(fd, PHN_SET_REG, & reg);
-    assert(ret == 0);
-
-    return 0;
-}
-\end{minted}
-\end{frame}
-
-\begin{frame}[fragile]
-  \frametitle{File Operations Definition: Example 3/3}
-  \begin{itemize}
-  \item Defining a \code{file_operations} structure:
-\begin{minted}{c}
-#include <linux/fs.h>
-static struct file_operations acme_fops =
-{
-    .owner = THIS_MODULE,
-    .read = acme_read,
-    .write = acme_write,
-};
-\end{minted}
-  \item You just need to supply the functions you implemented!
-    Defaults for other functions (such as \code{open}, \code{release}...) are fine
-    if you do not implement anything special.
-  \end{itemize}
-\end{frame}
-
-\begin{frame}
-  \frametitle{dev\_t data type}
-  \begin{itemize}
-  \item Kernel data type to represent a major / minor number pair
-    \begin{itemize}
-    \item Also called a \emph{device number}.
-    \item Defined in \code{linux/kdev_t.h}
-    \item 32 bit size (major: 12 bits, minor: 20 bits)
-    \item Macro to compose the device number
-      \begin{itemize}
-      \item \code{MKDEV(int major, int minor);}
-      \end{itemize}
-    \item Macro to extract the minor and major numbers:
-      \begin{itemize}
-      \item \code{MAJOR(dev_t dev);}
-      \item \code{MINOR(dev_t dev);}
-      \end{itemize}
-  \end{itemize}
-\end{itemize}
-\end{frame}
-
-\begin{frame}[fragile]
-  \frametitle{Registering device numbers 1/2}
-\begin{minted}[fontsize=\small]{c}
-#include <linux/fs.h>
-int register_chrdev_region(
-        dev_t from,        /* Starting device number */
-        unsigned count,    /* Number of device numbers */
-        const char *name); /* Registered name */
-\end{minted}
-Returns \code{0} if the allocation was successful.\\
-Example
-\begin{minted}[fontsize=\small]{c}
-static dev_t acme_dev = MKDEV(202, 128);
-
-if (register_chrdev_region(acme_dev, acme_count, "acme")) {
-        pr_err("Failed to allocate device number\n");
-...
-\end{minted}
-\end{frame}
-
-\begin{frame}
-  \frametitle{Registering device numbers 2/2}
-  \begin{itemize}
-  \item If you don't have fixed device numbers assigned to your driver
-    \begin{itemize}
-    \item Better not to choose arbitrary ones. There could be
-      conflicts with other drivers.
-    \item The kernel API offers an \code{alloc_chrdev_region} function
-      to have the kernel allocate free ones for you. You can find the
-      allocated major number in \code{/proc/devices}.
-    \end{itemize}
-  \end{itemize}
-\end{frame}
-
-\begin{frame}[fragile]
-  \frametitle{Information on registered devices: /proc/devices}
-\begin{verbatim}
-Character devices:
-  1 mem
-  4 tty
-  4 ttyS
-  5 /dev/tty
-  5 /dev/console
-...
-
-Block devices:
-  1 ramdisk
-  7 loop
-  8 sd
-  9 md
- 11 sr
-179 mmc
-254 mdp
-...
-\end{verbatim}
-\end{frame}
-
-\begin{frame}[fragile]
-  \frametitle{Character device registration 1/2}
-  \begin{itemize}
-  \item The kernel represents character drivers with a \code{cdev} structure
-  \item Declare this structure globally (within your module):
-\begin{minted}{c}
-#include <linux/cdev.h>
-
-static struct cdev acme_cdev;
-\end{minted}
-  \item In the \emph{init} function, initialize the structure:
-\begin{minted}{c}
-cdev_init(&acme_cdev, &acme_fops);
-\end{minted}
-\end{itemize}
-\end{frame}
-
-\begin{frame}[fragile]
-  \frametitle{Character device registration 2/2}
-  \begin{itemize}
-  \item Then, now that your structure is ready, add it to the system:
-\begin{minted}[fontsize=\small]{c}
-int cdev_add(
-    struct cdev *p,  /* Character device structure */
-    dev_t dev,       /* Starting device major/minor */
-    unsigned count); /* Number of devices */
-\end{minted}
-  \item After this function call, the kernel knows the association
-  between the major/minor numbers and the file operations. Your device
-  is ready to be used!
-  \item Example (continued):
-\end{itemize}
-\begin{minted}[fontsize=\small]{c}
-if (cdev_add(&acme_cdev, acme_dev, acme_count)) {
-    printk (KERN_ERR "Char driver registration failed\n");
-    ...
-\end{minted}
-\end{frame}
-
-\begin{frame}[fragile]
-  \frametitle{Character device unregistration}
-  \begin{itemize}
-  \item First delete your character device
-    \begin{itemize}
-    \item \mint{c}+void cdev_del(struct cdev *p);+
-    \end{itemize}
-  \item Then, and only then, free the device number
-    \begin{itemize}
-    \item \mint{c}+void unregister_chrdev_region(dev_t from,+
-      \mint{c}+unsigned count);+
-    \end{itemize}
-  \item Example (continued):
-\begin{minted}{c}
-cdev_del(&acme_cdev);
-unregister_chrdev_region(acme_dev, acme_count);
-\end{minted}
-  \end{itemize}
-\end{frame}
-
-\begin{frame}
-  \frametitle{Linux error codes}
-  \begin{itemize}
-  \item The kernel convention for error management is
-    \begin{itemize}
-    \item Return \code{0} on success
-    \item Return a negative error code on failure
-    \end{itemize}
-  \item Error codes (from Linux 3.7 on):
-    \begin{itemize}
-    \item \code{include/uapi/asm-generic/errno-base.h}
-    \item \code{include/uapi/asm-generic/errno.h}
-    \end{itemize}
-  \end{itemize}
-\end{frame}
-
-\begin{frame}[fragile]
-  \frametitle{Char driver example summary 1/4}
-\begin{minted}[fontsize=\small]{c}
-static void *acme_buf;
-static int acme_bufsize = 8192;
-
-static int acme_count = 1;
-static dev_t acme_dev = MKDEV(202, 128);
-
-static struct cdev acme_cdev;
-
-static ssize_t acme_read(...) {...}
-static ssize_t acme_write(...) {...}
-
-static const struct file_operations acme_fops = {
-        .owner = THIS_MODULE,
-        .read = acme_read,
-        .write = acme_write,
-};
-\end{minted}
-\end{frame}
-
-\begin{frame}[fragile]
-  \frametitle{Char driver example summary 2/4}
-\begin{minted}[fontsize=\tiny]{c}
-static int __init acme_init(void)
-{
-        int err;
-        acme_buf = ioremap(ACME_PHYS, acme_bufsize);
-
-        if (!acme_buf) {
-                err = -ENOMEM;
-                goto err_exit;
-        }
-
-        if (register_chrdev_region(acme_dev, acme_count, "acme")) {
-                err = -ENODEV;
-                goto err_free_buf;
-        }
-
-        cdev_init(&acme_cdev, &acme_fops);
-
-        if (cdev_add(&acme_cdev, acme_dev, acme_count)) {
-                err = -ENODEV;
-                goto err_dev_unregister;
-        }
-
-        return 0;
-
- err_dev_unregister:
-        unregister_chrdev_region(acme_dev, acme_count);
- err_free_buf:
-        iounmap(acme_buf);
- err_exit:
-        return err;
-}
-\end{minted}
-\end{frame}
-
-\begin{frame}[fragile]
-  \frametitle{Character Driver Example Summary 3/4}
-\begin{minted}[fontsize=\small]{c}
-static void __exit acme_exit(void)
-{
-        cdev_del(&acme_cdev);
-        unregister_chrdev_region(acme_dev, acme_count);
-        iounmap(acme_buf);
-}
-
-module_init(acme_init);
-module_exit(acme_exit);    
-\end{minted}
-\end{frame}
-
-\begin{frame}
-\frametitle{Character Driver Example Summary 4/4}
-  \begin{itemize}
-  \item Kernel: character device writer
-    \begin{itemize}
-    \item Define the file operations callbacks for the device file:
-      \code{read}, \code{write}, \code{ioctl}, ...
-    \item In the module \emph{init} function, reserve major and minor numbers
-      with \code{register_chrdev_region()}, init a \code{cdev}
-      structure with your file operations and add it to the system
-      with \code{cdev_add()}.
-    \end{itemize}
-  \item User-space: system administration
-    \begin{itemize}
-    \item Load the character driver module
-    \item Create device files with matching major and minor numbers if
-      needed. The device file is ready to use!
-    \end{itemize}
-  \item User-space: system user
-    \begin{itemize}
-    \item Open the device file, read, write, or send ioctl's to it.
-    \end{itemize}
-  \item Kernel
-    \begin{itemize}
-    \item Executes the corresponding file operations
-    \end{itemize}
-  \end{itemize}
-\end{frame}
diff --git a/slides/kernel-driver-development-character-drivers/copy-to-from-user.dia b/slides/kernel-frameworks/copy-to-from-user.dia
similarity index 100%
rename from slides/kernel-driver-development-character-drivers/copy-to-from-user.dia
rename to slides/kernel-frameworks/copy-to-from-user.dia
diff --git a/slides/kernel-frameworks/kernel-frameworks.tex b/slides/kernel-frameworks/kernel-frameworks.tex
index ce7fa35..d7f94d6 100644
--- a/slides/kernel-frameworks/kernel-frameworks.tex
+++ b/slides/kernel-frameworks/kernel-frameworks.tex
@@ -19,7 +19,359 @@
 \end{frame}
 
 \begin{frame}
-  \frametitle{Kernel and Device Drivers}
+  \frametitle{Types of devices} Under Linux, there is essentially
+  three types of devices:
+  \begin{itemize}
+  \item {\bf Network devices}. They are represented as network
+    interfaces, visible in userspace using \code{ifconfig}.
+  \item {\bf Block devices}. They are used to provide userspace
+    applications access to raw storage devices (hard disks, USB
+    keys). They are visible to the applications as {\em device files}
+    in \code{/dev}.
+  \item {\bf Character devices}. They are used to provide userspace
+    applications access to all other types of devices (input, sound,
+    graphics, serial, etc.). They are also visible to the applications
+    as {\em device files} in \code{/dev}.
+  \end{itemize}
+  $\rightarrow$ Most devices are {\em character devices}, so we will
+  study those in more details.
+\end{frame}
+
+\begin{frame}
+  \frametitle{Major and minor numbers}
+  \begin{itemize}
+  \item Within the kernel, all block and character devices are
+    identified using a {\em major} and a {\em minor} number.
+  \item The {\em major number} typically indicates the family of the
+    device.
+  \item The {\em minor number} typically indicates the number of the
+    device (when they are for example several serial ports)
+  \item Major and minor numbers are statically allocated, and
+    identical accross all Linux systems.
+  \item They are defined in \kerneldoc{devices.txt}.
+  \end{itemize}
+\end{frame}
+
+\begin{frame}
+  \frametitle{Devices: everything is a file}
+  \begin{itemize}
+  \item A very important Unix design decision was to represent most of
+    the ``system objects'' as files
+  \item It allows applications to manipulate all “system objects” with
+    the normal file API (\code{open}, \code{read}, \code{write},
+    \code{close}, etc.)
+  \item So, devices had to be represented as files to the applications
+  \item This is done through a special artifact called a {\bf device
+      file}
+  \item It is a special type of file, that associates a file name
+    visible to userspace applications to the triplet {\em (type,
+      major, minor)} that the kernel understands
+  \item All {\em device files} are by convention stored in the
+    \code{/dev} directory
+  \end{itemize}
+\end{frame}
+
+\begin{frame}[fragile]
+\frametitle{Device files examples}
+
+Example of device files in a Linux system
+
+\small
+\begin{verbatim}
+$ ls -l /dev/ttyS0 /dev/tty1 /dev/sda1 /dev/sda2 /dev/zero
+brw-rw---- 1 root disk    8,  1 2011-05-27 08:56 /dev/sda1
+brw-rw---- 1 root disk    8,  2 2011-05-27 08:56 /dev/sda2
+crw------- 1 root root    4,  1 2011-05-27 08:57 /dev/tty1
+crw-rw---- 1 root dialout 4, 64 2011-05-27 08:56 /dev/ttyS0
+crw-rw-rw- 1 root root    1,  5 2011-05-27 08:56 /dev/zero
+\end{verbatim}
+\normalsize
+
+Example C code that uses the usual file API to write data to a serial port
+
+\small
+\begin{minted}{c}
+int fd;
+fd = open("/dev/ttyS0", O_RDWR);
+write(fd, "Hello", 5);
+close(fd);
+\end{minted}
+\end{frame}
+
+\begin{frame}
+  \frametitle{Creating device files}
+  \begin{itemize}
+    \item On a basic Linux system, the device files have to be created
+    manually using the \code{mknod} command
+    \begin{itemize}
+    \item \code{mknod /dev/<device> [c|b] major minor}
+    \item Needs root privileges
+    \item Coherency between device files and devices handled by the
+      kernel is left to the system developer
+    \end{itemize}
+  \item On more elaborate Linux systems, mechanisms can be added to
+    create/remove them automatically when devices appear and disappear
+    \begin{itemize}
+    \item \code{devtmpfs} virtual filesystem, since kernel 2.6.32
+    \item \code{udev} daemon, solution used by desktop and server Linux
+      systems
+    \item \code{mdev} program, a lighter solution than \code{udev}
+    \end{itemize}
+  \end{itemize}
+\end{frame}
+
+\begin{frame}
+  \frametitle{A character driver in the kernel}
+  \begin{itemize}
+  \item From the point of view of an application, a {\em character
+      device} is essentially a {\bf file}.
+  \item The driver of a character device must therefore implement {\bf
+      operations} that let applications think the device is a file:
+    \code{open}, \code{close}, \code{read}, \code{write}, etc.
+  \item In order to achieve this, a character driver must implement
+    the operations described in the \kstruct{file_operations}
+    structure and register them.
+  \item The Linux filesystem layer will ensure that the driver's
+    operations are called when an userspace application makes the
+    corresponding system call.
+  \end{itemize}
+\end{frame}
+
+\begin{frame}
+  \frametitle{From userspace to the kernel: character devices}
+  \begin{center}
+    \includegraphics[width=\textwidth]{slides/kernel-frameworks/user-kernel-exchanges.pdf}
+  \end{center}
+\end{frame}
+
+\begin{frame}[fragile]
+  \frametitle{File operations}
+  \begin{itemize}
+  \item Here are the most important operations for a character
+    driver. All of them are optional.
+  \end{itemize}
+\begin{minted}[fontsize=\footnotesize]{c}
+struct file_operations {
+    ssize_t (*read) (struct file *, char __user *,
+        size_t, loff_t *);
+    ssize_t (*write) (struct file *, const char __user *,
+        size_t, loff_t *);
+    long (*unlocked_ioctl) (struct file *, unsigned int,
+        unsigned long);
+    int (*mmap) (struct file *, struct vm_area_struct *);
+    int (*open) (struct inode *, struct file *);
+    int (*release) (struct inode *, struct file *);
+};
+\end{minted}
+\end{frame}
+
+\begin{frame}[fragile]
+  \frametitle{open() and release()}
+  \begin{itemize}
+  \item \mint{c}+int foo_open(struct inode *i, struct file *f)+
+    \begin{itemize}
+    \item Called when user-space opens the device file.
+    \item \code{inode} is a structure that uniquely represent a file
+      in the system (be it a regular file, a directory, a symbolic
+      link, a character or block device)
+    \item \code{file} is a structure created every time a file is
+      opened. Several file structures can point to the same
+      \code{inode} structure.
+      \begin{itemize}
+      \item Contains information like the current position, the
+        opening mode, etc.
+      \item Has a \code{void *private_data} pointer that one can
+        freely use.
+      \item A pointer to the file structure is passed to all other
+        operations
+      \end{itemize}
+    \end{itemize}
+  \item \mint{c}+int foo_release(struct inode *i, struct file *f)+
+    \begin{itemize}
+    \item Called when user-space closes the file.
+    \end{itemize}
+  \end{itemize}
+\end{frame}
+
+\begin{frame}
+  \frametitle{read()}
+  \begin{itemize}
+  \item \mint{c}+ssize_t foo_read(struct file *f, __user char *buf,+
+    \mint{c}+size_t sz, loff_t *off)+
+    \begin{itemize}
+    \item Called when user-space uses the \code{read()} system call on
+      the device.
+    \item Must read data from the device, write at most \code{sz}
+      bytes in the user-space buffer \code{buf}, and update the
+      current position in the file \code{off}. \code{f} is a pointer
+      to the same file structure that was passed in the \code{open()}
+      operation
+    \item Must return the number of bytes read.
+    \item On UNIX, \code{read()} operations typically block when there
+      isn't enough data to read from the device
+    \end{itemize}
+  \end{itemize}
+\end{frame}
+
+\begin{frame}[fragile]
+  \frametitle{write()}
+  \begin{itemize}
+  \item \mint{c}+ssize_t foo_write(struct file *f,+
+    \mint{c}+__user const char *buf, size_t sz, loff_t *off)+
+    \begin{itemize}
+    \item Called when user-space uses the \code{write()} system call
+      on the device
+    \item The opposite of \code{read}, must read at most \code{sz}
+      bytes from \code{buf}, write it to the device, update \code{off}
+      and return the number of bytes written.
+    \end{itemize}
+  \end{itemize}
+\end{frame}
+
+\begin{frame}
+  \frametitle{Exchanging data with user-space 1/3}
+  \begin{itemize}
+  \item Kernel code isn't allowed to directly access user-space
+    memory, using \code{memcpy} or direct pointer dereferencing
+    \begin{itemize}
+    \item Doing so does not work on some architectures
+    \item If the address passed by the application was invalid, the
+      application would segfault.
+    \end{itemize}
+  \item To keep the kernel code portable and have proper error
+    handling, your driver must use special kernel functions to
+    exchange data with user-space.
+  \end{itemize}
+\end{frame}
+
+\begin{frame}[fragile]
+  \frametitle{Exchanging data with user-space 2/3}
+  \begin{itemize}
+  \item A single value
+    \begin{itemize}
+    \item \code{get_user(v, p);}
+      \begin{itemize}
+      \item The kernel variable \code{v} gets the value pointed by the
+        user-space pointer \code{p}
+      \end{itemize}
+    \item \code{put_user(v, p);}
+      \begin{itemize}
+      \item The value pointed by the user-space pointer \code{p} is
+        set to the contents of the kernel variable \code{v}.
+      \end{itemize}
+    \end{itemize}
+  \item A buffer
+    \begin{itemize}
+    \item \mint{c}+unsigned long copy_to_user(void __user *to,+
+      \mint{c}+const void *from, unsigned long n);+
+    \item \mint{c}+unsigned long copy_from_user(void *to,+
+      \mint{c}+const void __user *from, unsigned long n);+
+    \end{itemize}
+  \item The return value must be checked. Zero on success, non-zero on
+    failure. If non-zero, the convention is to return -\code{EFAULT}.
+  \end{itemize}
+\end{frame}
+
+\begin{frame}
+ \frametitle{Exchanging data with user-space 3/3}
+ \begin{center}
+    \includegraphics[width=\textwidth]{slides/kernel-frameworks/copy-to-from-user.pdf}
+ \end{center}
+\end{frame}
+
+\begin{frame}
+  \frametitle{Zero copy access to user memory}
+  \begin{itemize}
+  \item Having to copy data to our from an intermediate kernel buffer
+    can become expensive when the amount of data to transfer is
+    important (video).
+  \item \emph{Zero copy} options are possible:
+    \begin{itemize}
+    \item \code{mmap()} system call to allow user space to directly
+      access memory mapped I/O space.
+    \item \code{get_user_pages()} to get a mapping to user pages
+      without having to copy them. See \url{http://j.mp/oPW6Fb}
+      (Kernel API doc). This API is more complex to use though.
+    \end{itemize}
+  \end{itemize}
+\end{frame}
+
+\begin{frame}[fragile]
+  \frametitle{unlocked\_ioctl()}
+  \begin{itemize}
+  \item \mint{c}+long unlocked_ioctl(struct file *f,+
+    \mint{c}+unsigned int cmd, unsigned long arg)+
+    \begin{itemize}
+    \item Associated to the \code{ioctl()} system call.
+    \item Called unlocked because it didn't hold the Big Kernel Lock
+      (gone now).
+    \item Allows to extend the driver capabilities beyond the limited
+      read/write API.
+    \item For example: changing the speed of a serial port, setting
+      video output format, querying a device serial number...
+    \item \code{cmd} is a number identifying the operation to perform
+    \item \code{arg} is the optional argument passed as third argument
+      of the \code{ioctl()} system call. Can be an integer, an
+      address, etc.
+    \item The semantic of \code{cmd} and \code{arg} is
+      driver-specific.
+    \end{itemize}
+  \end{itemize}
+\end{frame}
+
+\begin{frame}[fragile]
+  \frametitle{ioctl() example: kernel side}
+\begin{minted}[fontsize=\tiny]{c}
+static long phantom_ioctl(struct file *file, unsigned int cmd,
+    unsigned long arg)
+{
+    struct phm_reg r;
+    void __user *argp = (void __user *)arg;
+
+    switch (cmd) {
+    case PHN_SET_REG:
+        if (copy_from_user(&r, argp, sizeof(r)))
+            return -EFAULT;
+        /* Do something */
+        break;
+    case PHN_GET_REG:
+        if (copy_to_user(argp, &r, sizeof(r)))
+            return -EFAULT;
+        /* Do something */
+        break;
+    default:
+        return -ENOTTY;
+    }
+
+    return 0; }
+\end{minted}
+Selected excerpt from \code{drivers/misc/phantom.c}
+\end{frame}
+
+\begin{frame}[fragile]
+  \frametitle{Ioctl() Example: Application Side}
+\begin{minted}{c}
+int main(void)
+{
+    int fd, ret;
+    struct phm_reg reg;
+
+    fd = open("/dev/phantom");
+    assert(fd > 0);
+
+    reg.field1 = 42;
+    reg.field2 = 67;
+
+    ret = ioctl(fd, PHN_SET_REG, & reg);
+    assert(ret == 0);
+
+    return 0;
+}
+\end{minted}
+\end{frame}
+
+\begin{frame}
+  \frametitle{Beyond character drivers: kernel frameworks}
   \begin{itemize}
   \item Many device drivers are not implemented directly as character
     drivers
@@ -34,9 +386,6 @@
       interface (\code{ioctl}, etc.) for every type of device,
       regardless of the driver
     \end{itemize}
-  \item The device drivers rely on the \emph{bus infrastructure} to
-    enumerate the devices and communicate with them, this is called
-    the {\em device model}.
   \end{itemize}
 \end{frame}
 
diff --git a/slides/kernel-driver-development-character-drivers/user-kernel-exchanges.dia b/slides/kernel-frameworks/user-kernel-exchanges.dia
similarity index 100%
rename from slides/kernel-driver-development-character-drivers/user-kernel-exchanges.dia
rename to slides/kernel-frameworks/user-kernel-exchanges.dia



More information about the training-materials-updates mailing list