\subsection{mmap}

\begin{frame}
  \frametitle{mmap}
  \begin{itemize}
  \item Possibility to have parts of the virtual address space of a
    program mapped to the contents of a file
  \item Particularly useful when the file is a device file
  \item Allows to access device I/O memory and ports without having to
    go through (expensive) read, write or ioctl calls
  \item One can access to current mapped files by two means:
    \begin{itemize}
    \item \code{/proc/<pid>/maps}
    \item \code{pmap <pid>}
    \end{itemize}
  \end{itemize}
\end{frame}

\begin{frame}[fragile]
  \frametitle{/proc/\textless pid\textgreater/maps}
{\tiny
\begin{verbatim}
       start-end          perm offset major:minor inode  mapped file name
...
7f4516d04000-7f4516d06000 rw-s 1152a2000 00:05 8406   /dev/dri/card0
7f4516d07000-7f4516d0b000 rw-s 120f9e000 00:05 8406   /dev/dri/card0
...
7f4518728000-7f451874f000 r-xp 00000000 08:01 268909  /lib/x86_64-linux-gnu/libexpat.so.1.5.2
7f451874f000-7f451894f000 ---p 00027000 08:01 268909  /lib/x86_64-linux-gnu/libexpat.so.1.5.2
7f451894f000-7f4518951000 r--p 00027000 08:01 268909  /lib/x86_64-linux-gnu/libexpat.so.1.5.2
7f4518951000-7f4518952000 rw-p 00029000 08:01 268909  /lib/x86_64-linux-gnu/libexpat.so.1.5.2
...
7f451da4f000-7f451dc3f000 r-xp 00000000 08:01 1549    /usr/bin/Xorg
7f451de3e000-7f451de41000 r--p 001ef000 08:01 1549    /usr/bin/Xorg
7f451de41000-7f451de4c000 rw-p 001f2000 08:01 1549    /usr/bin/Xorg
...
\end{verbatim}
}
\end{frame}

\begin{frame}
  \frametitle{mmap Overview}
  \begin{center}
    \includegraphics[height=0.8\textheight]{slides/kernel-driver-development-mmap/mmap-overview.pdf}
  \end{center}
\end{frame}

\begin{frame}[fragile]
  \frametitle{How to Implement mmap - User Space}
  \begin{itemize}
  \item Open the device file
  \item Call the \code{mmap} system call (see \code{man mmap} for
    details):
    \begin{minted}[fontsize=\footnotesize]{c}
void * mmap(
    void *start,   /* Often 0, preferred starting address */
    size_t length, /* Length of the mapped area */
    int prot,      /* Permissions: read, write, execute */
    int flags,     /* Options: shared mapping, private copy... */
    int fd,        /* Open file descriptor */
    off_t offset   /* Offset in the file */
);
    \end{minted}
  \item You get a virtual address you can write to or read from.
  \end{itemize}
\end{frame}

\begin{frame}[fragile]
  \frametitle{How to Implement mmap - Kernel Space}
  \begin{itemize}
  \item Character driver: implement an \code{mmap} file operation and add it
    to the driver file operations:
    \begin{minted}[fontsize=\small]{c}
int (*mmap) (
    struct file *,           /* Open file structure */
    struct vm_area_struct *  /* Kernel VMA structure */
);
    \end{minted}
  \item Initialize the mapping.
    \begin{itemize}
    \item Can be done in most cases with the \code{remap_pfn_range()}
      function, which takes care of most of the job.
    \end{itemize}
  \end{itemize}
\end{frame}

\begin{frame}[fragile]
  \frametitle{remap\_pfn\_range()}
  \begin{itemize}
  \item pfn: page frame number
  \item The most significant bits of the page address (without the
    bits corresponding to the page size).
  \end{itemize}
  \begin{minted}[fontsize=\small]{c}
#include <linux/mm.h>

int remap_pfn_range(
    struct vm_area_struct *, /* VMA struct */
    unsigned long virt_addr, /* Starting user
                              * virtual address */
    unsigned long pfn,       /* pfn of the starting
                              * physical address */
    unsigned long size,      /* Mapping size */
    pgprot_t                 /* Page permissions */
);
  \end{minted}
\end{frame}

\begin{frame}[fragile]
  \frametitle{Simple mmap Implementation}
  \begin{minted}[fontsize=\small]{c}
static int acme_mmap
    (struct file * file, struct vm_area_struct *vma)
{
      size = vma->vm_end - vma->vm_start;

      if (size > ACME_SIZE)
          return -EINVAL;

      if (remap_pfn_range(vma,
                    vma->vm_start,
                    ACME_PHYS >> PAGE_SHIFT,
                    size,
                    vma->vm_page_prot))
          return -EAGAIN;

      return 0;
    }
  \end{minted}
\end{frame}

\begin{frame}
  \frametitle{devmem2}
  \begin{itemize}
  \item \url{http://free-electrons.com/pub/mirror/devmem2.c}, by Jan-Derk
    Bakker
  \item Very useful tool to directly peek (read) or poke
    (write) I/O addresses mapped in physical address space from a
    shell command line!
    \begin{itemize}
    \item Very useful for early interaction experiments with a device,
      without having to code and compile a driver.
    \item Uses \code{mmap} to \code{/dev/mem}.
    \item Examples (\code{b}: byte, \code{h}: half, \code{w}: word)
      \begin{itemize}
      \item \code{devmem2 0x000c0004 h} (reading)
      \item \code{devmem2 0x000c0008 w 0xffffffff} (writing)
      \end{itemize}
    \item \code{devmem} is now available in BusyBox, making it even easier to
      use.
    \end{itemize}
  \end{itemize}
\end{frame}

\begin{frame}
  \frametitle{mmap Summary}
  \begin{itemize}
  \item The device driver is loaded. It defines an \code{mmap} file
    operation.
  \item A user space process calls the \code{mmap} system call.
  \item The \code{mmap} file operation is called.
  \item It initializes the mapping using the device physical address.
  \item The process gets a starting address to read from and write to
    (depending on permissions).
  \item The MMU automatically takes care of converting the process
    virtual addresses into physical ones.
  \item Direct access to the hardware without any expensive
    \code{read} or \code{write} system calls
  \end{itemize}
\end{frame}

