mirror of
https://github.com/sysprog21/lkmpg.git
synced 2025-02-26 20:13:11 +08:00
5425 lines
722 KiB
HTML
5425 lines
722 KiB
HTML
<!DOCTYPE html>
|
|
<html lang='en-US' xml:lang='en-US'>
|
|
<head> <title>The Linux Kernel Module Programming Guide</title>
|
|
<meta charset='utf-8' />
|
|
<meta content='TeX4ht (https://tug.org/tex4ht/)' name='generator' />
|
|
<meta content='width=device-width,initial-scale=1' name='viewport' />
|
|
<link href='lkmpg-for-ht.css' rel='stylesheet' type='text/css' />
|
|
<meta content='lkmpg-for-ht.tex' name='src' />
|
|
<script src='https://buttons.github.io/buttons.js'></script> <div class='right'> <a aria-label='View on GitHub' class='github-button' data-size='large' href='https://github.com/sysprog21/lkmpg'>View on GitHub</a> <a aria-label='Download PDF document' class='github-button' data-icon='octicon-download' data-size='large' href='https://github.com/sysprog21/lkmpg/releases/download/latest/lkmpg.pdf'>Download PDF document</a> <br /><br /> </div>
|
|
</head><body>
|
|
<div class='maketitle'>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<h2 class='titleHead'>The Linux Kernel Module Programming Guide</h2>
|
|
<div class='author'><span class='ecrm-1200'>Peter Jay Salzman, Michael Burian, Ori Pomerantz, Bob Mottram, Jim Huang</span></div><br />
|
|
<div class='date'><span class='ecrm-1200'>September 10, 2021</span></div>
|
|
|
|
|
|
|
|
</div>
|
|
<div class='tableofcontents'>
|
|
<span class='sectionToc'>1 <a href='#introduction' id='QQ2-1-1'>Introduction</a></span>
|
|
<br /> <span class='subsectionToc'>1.1 <a href='#authorship' id='QQ2-1-2'>Authorship</a></span>
|
|
<br /> <span class='subsectionToc'>1.2 <a href='#acknowledgements' id='QQ2-1-3'>Acknowledgements</a></span>
|
|
<br /> <span class='subsectionToc'>1.3 <a href='#what-is-a-kernel-module' id='QQ2-1-4'>What Is A Kernel Module?</a></span>
|
|
<br /> <span class='subsectionToc'>1.4 <a href='#kernel-module-package' id='QQ2-1-5'>Kernel module package</a></span>
|
|
<br /> <span class='subsectionToc'>1.5 <a href='#what-modules-are-in-my-kernel' id='QQ2-1-6'>What Modules are in my Kernel?</a></span>
|
|
<br /> <span class='subsectionToc'>1.6 <a href='#do-i-need-to-download-and-compile-the-kernel' id='QQ2-1-7'>Do I need to download and compile the kernel?</a></span>
|
|
<br /> <span class='subsectionToc'>1.7 <a href='#before-we-begin' id='QQ2-1-8'>Before We Begin</a></span>
|
|
<br /> <span class='sectionToc'>2 <a href='#headers' id='QQ2-1-9'>Headers</a></span>
|
|
<br /> <span class='sectionToc'>3 <a href='#examples' id='QQ2-1-10'>Examples</a></span>
|
|
<br /> <span class='sectionToc'>4 <a href='#hello-world' id='QQ2-1-11'>Hello World</a></span>
|
|
<br /> <span class='subsectionToc'>4.1 <a href='#the-simplest-module' id='QQ2-1-12'>The Simplest Module</a></span>
|
|
<br /> <span class='subsectionToc'>4.2 <a href='#hello-and-goodbye' id='QQ2-1-13'>Hello and Goodbye</a></span>
|
|
<br /> <span class='subsectionToc'>4.3 <a href='#the-init-and-exit-macros' id='QQ2-1-14'>The __init and __exit Macros</a></span>
|
|
<br /> <span class='subsectionToc'>4.4 <a href='#licensing-and-module-documentation' id='QQ2-1-15'>Licensing and Module Documentation</a></span>
|
|
<br /> <span class='subsectionToc'>4.5 <a href='#passing-command-line-arguments-to-a-module' id='QQ2-1-16'>Passing Command Line Arguments to a Module</a></span>
|
|
<br /> <span class='subsectionToc'>4.6 <a href='#modules-spanning-multiple-files' id='QQ2-1-17'>Modules Spanning Multiple Files</a></span>
|
|
<br /> <span class='subsectionToc'>4.7 <a href='#building-modules-for-a-precompiled-kernel' id='QQ2-1-18'>Building modules for a precompiled kernel</a></span>
|
|
<br /> <span class='sectionToc'>5 <a href='#preliminaries' id='QQ2-1-19'>Preliminaries</a></span>
|
|
<br /> <span class='subsectionToc'>5.1 <a href='#how-modules-begin-and-end' id='QQ2-1-20'>How modules begin and end</a></span>
|
|
<br /> <span class='subsectionToc'>5.2 <a href='#functions-available-to-modules' id='QQ2-1-21'>Functions available to modules</a></span>
|
|
<br /> <span class='subsectionToc'>5.3 <a href='#user-space-vs-kernel-space' id='QQ2-1-22'>User Space vs Kernel Space</a></span>
|
|
<br /> <span class='subsectionToc'>5.4 <a href='#name-space' id='QQ2-1-23'>Name Space</a></span>
|
|
<br /> <span class='subsectionToc'>5.5 <a href='#code-space' id='QQ2-1-24'>Code space</a></span>
|
|
<br /> <span class='subsectionToc'>5.6 <a href='#device-drivers' id='QQ2-1-25'>Device Drivers</a></span>
|
|
<br /> <span class='sectionToc'>6 <a href='#character-device-drivers' id='QQ2-1-26'>Character Device drivers</a></span>
|
|
<br /> <span class='subsectionToc'>6.1 <a href='#the-fileoperations-structure' id='QQ2-1-27'>The file_operations Structure</a></span>
|
|
<br /> <span class='subsectionToc'>6.2 <a href='#the-file-structure' id='QQ2-1-28'>The file structure</a></span>
|
|
<br /> <span class='subsectionToc'>6.3 <a href='#registering-a-device' id='QQ2-1-29'>Registering A Device</a></span>
|
|
<br /> <span class='subsectionToc'>6.4 <a href='#unregistering-a-device' id='QQ2-1-30'>Unregistering A Device</a></span>
|
|
<br /> <span class='subsectionToc'>6.5 <a href='#chardevc' id='QQ2-1-31'>chardev.c</a></span>
|
|
<br /> <span class='subsectionToc'>6.6 <a href='#writing-modules-for-multiple-kernel-versions' id='QQ2-1-32'>Writing Modules for Multiple Kernel Versions</a></span>
|
|
<br /> <span class='sectionToc'>7 <a href='#the-proc-file-system' id='QQ2-1-33'>The /proc File System</a></span>
|
|
<br /> <span class='subsectionToc'>7.1 <a href='#the-procops-structure' id='QQ2-1-34'>The proc_ops Structure</a></span>
|
|
<br /> <span class='subsectionToc'>7.2 <a href='#read-and-write-a-proc-file' id='QQ2-1-35'>Read and Write a /proc File</a></span>
|
|
<br /> <span class='subsectionToc'>7.3 <a href='#manage-proc-file-with-standard-filesystem' id='QQ2-1-36'>Manage /proc file with standard filesystem</a></span>
|
|
<br /> <span class='subsectionToc'>7.4 <a href='#manage-proc-file-with-seqfile' id='QQ2-1-37'>Manage /proc file with seq_file</a></span>
|
|
<br /> <span class='sectionToc'>8 <a href='#sysfs-interacting-with-your-module' id='QQ2-1-39'>sysfs: Interacting with your module</a></span>
|
|
<br /> <span class='sectionToc'>9 <a href='#talking-to-device-files' id='QQ2-1-40'>Talking To Device Files</a></span>
|
|
<br /> <span class='sectionToc'>10 <a href='#system-calls' id='QQ2-1-41'>System Calls</a></span>
|
|
<br /> <span class='sectionToc'>11 <a href='#blocking-processes-and-threads' id='QQ2-1-42'>Blocking Processes and threads</a></span>
|
|
|
|
|
|
|
|
<br /> <span class='subsectionToc'>11.1 <a href='#sleep' id='QQ2-1-43'>Sleep</a></span>
|
|
<br /> <span class='subsectionToc'>11.2 <a href='#completions' id='QQ2-1-44'>Completions</a></span>
|
|
<br /> <span class='sectionToc'>12 <a href='#avoiding-collisions-and-deadlocks' id='QQ2-1-45'>Avoiding Collisions and Deadlocks</a></span>
|
|
<br /> <span class='subsectionToc'>12.1 <a href='#mutex' id='QQ2-1-46'>Mutex</a></span>
|
|
<br /> <span class='subsectionToc'>12.2 <a href='#spinlocks' id='QQ2-1-47'>Spinlocks</a></span>
|
|
<br /> <span class='subsectionToc'>12.3 <a href='#read-and-write-locks' id='QQ2-1-48'>Read and write locks</a></span>
|
|
<br /> <span class='subsectionToc'>12.4 <a href='#atomic-operations' id='QQ2-1-49'>Atomic operations</a></span>
|
|
<br /> <span class='sectionToc'>13 <a href='#replacing-print-macros' id='QQ2-1-50'>Replacing Print Macros</a></span>
|
|
<br /> <span class='subsectionToc'>13.1 <a href='#replacement' id='QQ2-1-51'>Replacement</a></span>
|
|
<br /> <span class='subsectionToc'>13.2 <a href='#flashing-keyboard-leds' id='QQ2-1-52'>Flashing keyboard LEDs</a></span>
|
|
<br /> <span class='sectionToc'>14 <a href='#scheduling-tasks' id='QQ2-1-53'>Scheduling Tasks</a></span>
|
|
<br /> <span class='subsectionToc'>14.1 <a href='#tasklets' id='QQ2-1-54'>Tasklets</a></span>
|
|
<br /> <span class='subsectionToc'>14.2 <a href='#work-queues' id='QQ2-1-55'>Work queues</a></span>
|
|
<br /> <span class='sectionToc'>15 <a href='#interrupt-handlers' id='QQ2-1-56'>Interrupt Handlers</a></span>
|
|
<br /> <span class='subsectionToc'>15.1 <a href='#interrupt-handlers1' id='QQ2-1-57'>Interrupt Handlers</a></span>
|
|
<br /> <span class='subsectionToc'>15.2 <a href='#detecting-button-presses' id='QQ2-1-58'>Detecting button presses</a></span>
|
|
<br /> <span class='subsectionToc'>15.3 <a href='#bottom-half' id='QQ2-1-59'>Bottom Half</a></span>
|
|
<br /> <span class='sectionToc'>16 <a href='#crypto' id='QQ2-1-60'>Crypto</a></span>
|
|
<br /> <span class='subsectionToc'>16.1 <a href='#hash-functions' id='QQ2-1-61'>Hash functions</a></span>
|
|
<br /> <span class='subsectionToc'>16.2 <a href='#symmetric-key-encryption' id='QQ2-1-62'>Symmetric key encryption</a></span>
|
|
<br /> <span class='sectionToc'>17 <a href='#standardizing-the-interfaces-the-device-model' id='QQ2-1-63'>Standardizing the interfaces: The Device Model</a></span>
|
|
<br /> <span class='sectionToc'>18 <a href='#optimizations' id='QQ2-1-64'>Optimizations</a></span>
|
|
<br /> <span class='subsectionToc'>18.1 <a href='#likely-and-unlikely-conditions' id='QQ2-1-65'>Likely and Unlikely conditions</a></span>
|
|
<br /> <span class='sectionToc'>19 <a href='#common-pitfalls' id='QQ2-1-66'>Common Pitfalls</a></span>
|
|
<br /> <span class='subsectionToc'>19.1 <a href='#using-standard-libraries' id='QQ2-1-67'>Using standard libraries</a></span>
|
|
<br /> <span class='subsectionToc'>19.2 <a href='#disabling-interrupts' id='QQ2-1-68'>Disabling interrupts</a></span>
|
|
<br /> <span class='sectionToc'>20 <a href='#where-to-go-from-here' id='QQ2-1-69'>Where To Go From Here?</a></span>
|
|
</div>
|
|
<h3 class='sectionHead' id='introduction'><span class='titlemark'>1 </span> <a id='x1-10001'></a>Introduction</h3>
|
|
<!-- l. 56 --><p class='noindent'>The Linux Kernel Module Programming Guide is a free book; you may reproduce
|
|
and/or modify it under the terms of the <a href='https://opensource.org/licenses/OSL-3.0'>Open Software License</a>, version
|
|
3.0.
|
|
</p><!-- l. 58 --><p class='indent'> This book is distributed in the hope it will be useful, but without any warranty,
|
|
without even the implied warranty of merchantability or fitness for a particular
|
|
purpose.
|
|
</p><!-- l. 60 --><p class='indent'> The author encourages wide distribution of this book for personal or commercial
|
|
use, provided the above copyright notice remains intact and the method adheres to
|
|
the provisions of the <a href='https://opensource.org/licenses/OSL-3.0'>Open Software License</a>. In summary, you may copy and
|
|
distribute this book free of charge or for a profit. No explicit permission is required
|
|
from the author for reproduction of this book in any medium, physical or
|
|
electronic.
|
|
</p><!-- l. 63 --><p class='indent'> Derivative works and translations of this document must be placed under the
|
|
Open Software License, and the original copyright notice must remain intact. If you
|
|
have contributed new material to this book, you must make the material and source
|
|
code available for your revisions. Please make revisions and updates available directly
|
|
|
|
|
|
|
|
to the document maintainer, Jim Huang <jserv@ccns.ncku.edu.tw>. This will allow
|
|
for the merging of updates and provide consistent revisions to the Linux
|
|
community.
|
|
</p><!-- l. 68 --><p class='indent'> If you publish or distribute this book commercially, donations, royalties, and/or
|
|
printed copies are greatly appreciated by the author and the <a href='https://tldp.org/'>Linux Documentation
|
|
Project</a> (LDP). Contributing in this way shows your support for free software and
|
|
the LDP. If you have questions or comments, please contact the address
|
|
above.
|
|
</p><!-- l. 71 --><p class='noindent'>
|
|
</p>
|
|
<h4 class='subsectionHead' id='authorship'><span class='titlemark'>1.1 </span> <a id='x1-20001.1'></a>Authorship</h4>
|
|
<!-- l. 74 --><p class='noindent'>The Linux Kernel Module Programming Guide was originally written for the 2.2
|
|
kernels by Ori Pomerantz. Eventually, Ori no longer had time to maintain the
|
|
document. After all, the Linux kernel is a fast moving target. Peter Jay Salzman took
|
|
over maintenance and updated it for the 2.4 kernels. Eventually, Peter no longer had
|
|
time to follow developments with the 2.6 kernel, so Michael Burian became a
|
|
co-maintainer to update the document for the 2.6 kernels. Bob Mottram updated the
|
|
examples for 3.8+ kernels. Jim Huang upgraded to recent kernel versions (v5.x) and
|
|
revised the LaTeX document.
|
|
</p><!-- l. 82 --><p class='noindent'>
|
|
</p>
|
|
<h4 class='subsectionHead' id='acknowledgements'><span class='titlemark'>1.2 </span> <a id='x1-30001.2'></a>Acknowledgements</h4>
|
|
<!-- l. 85 --><p class='noindent'>The following people have contributed corrections or good suggestions: Ignacio
|
|
Martin, David Porter, Daniele Paolo Scarpazza, Dimo Velev, Francois Audeon, Horst
|
|
Schirmeier, and Roman Lakeev.
|
|
</p><!-- l. 87 --><p class='noindent'>
|
|
</p>
|
|
<h4 class='subsectionHead' id='what-is-a-kernel-module'><span class='titlemark'>1.3 </span> <a id='x1-40001.3'></a>What Is A Kernel Module?</h4>
|
|
<!-- l. 90 --><p class='noindent'>So, you want to write a kernel module. You know C, you have written a few normal
|
|
programs to run as processes, and now you want to get to where the real action is, to
|
|
where a single wild pointer can wipe out your file system and a core dump means a
|
|
reboot.
|
|
</p><!-- l. 93 --><p class='indent'> What exactly is a kernel module? Modules are pieces of code that can be loaded
|
|
and unloaded into the kernel upon demand. They extend the functionality of the
|
|
kernel without the need to reboot the system. For example, one type of module is the
|
|
device driver, which allows the kernel to access hardware connected to the system.
|
|
Without modules, we would have to build monolithic kernels and add new
|
|
functionality directly into the kernel image. Besides having larger kernels, this has
|
|
the disadvantage of requiring us to rebuild and reboot the kernel every time we want
|
|
|
|
|
|
|
|
new functionality.
|
|
</p><!-- l. 100 --><p class='noindent'>
|
|
</p>
|
|
<h4 class='subsectionHead' id='kernel-module-package'><span class='titlemark'>1.4 </span> <a id='x1-50001.4'></a>Kernel module package</h4>
|
|
<!-- l. 103 --><p class='noindent'>Linux distributions provide the commands
|
|
<code> <span class='ectt-1000'>modprobe</span>
|
|
</code>, <code> <span class='ectt-1000'>insmod</span>
|
|
</code> and <code> <span class='ectt-1000'>depmod</span>
|
|
</code> within a package.
|
|
</p><!-- l. 105 --><p class='indent'> On Ubuntu/Debian:
|
|
</p>
|
|
<pre class='fancyvrb' id='fancyvrb1'><a id='x1-5006r1'></a><span class='ecrm-0500'>1</span><span class='ectt-1000'>sudo apt-get install build-essential kmod</span></pre>
|
|
<!-- l. 110 --><p class='indent'> On Arch Linux:
|
|
</p>
|
|
<pre class='fancyvrb' id='fancyvrb2'><a id='x1-5009r1'></a><span class='ecrm-0500'>1</span><span class='ectt-1000'>sudo pacman -S gcc kmod</span></pre>
|
|
<!-- l. 115 --><p class='noindent'>
|
|
</p>
|
|
<h4 class='subsectionHead' id='what-modules-are-in-my-kernel'><span class='titlemark'>1.5 </span> <a id='x1-60001.5'></a>What Modules are in my Kernel?</h4>
|
|
<!-- l. 118 --><p class='noindent'>To discover what modules are already loaded within your current kernel use the command
|
|
<code> <span class='ectt-1000'>lsmod</span>
|
|
</code>.
|
|
</p>
|
|
<pre class='fancyvrb' id='fancyvrb3'><a id='x1-6004r1'></a><span class='ecrm-0500'>1</span><span class='ectt-1000'>sudo lsmod</span></pre>
|
|
<!-- l. 123 --><p class='indent'> Modules are stored within the file <span class='obeylines-h'><span class='verb'><span class='ectt-1000'>/proc/modules</span></span></span>, so you can also see them with:
|
|
|
|
</p>
|
|
<pre class='fancyvrb' id='fancyvrb4'><a id='x1-6007r1'></a><span class='ecrm-0500'>1</span><span class='ectt-1000'>sudo cat /proc/modules</span></pre>
|
|
<!-- l. 128 --><p class='indent'> This can be a long list, and you might prefer to search for something particular.
|
|
To search for the <span class='obeylines-h'><span class='verb'><span class='ectt-1000'>fat</span></span></span> module:
|
|
|
|
|
|
|
|
</p>
|
|
<pre class='fancyvrb' id='fancyvrb5'><a id='x1-6010r1'></a><span class='ecrm-0500'>1</span><span class='ectt-1000'>sudo lsmod | grep fat</span></pre>
|
|
<!-- l. 134 --><p class='noindent'>
|
|
</p>
|
|
<h4 class='subsectionHead' id='do-i-need-to-download-and-compile-the-kernel'><span class='titlemark'>1.6 </span> <a id='x1-70001.6'></a>Do I need to download and compile the kernel?</h4>
|
|
<!-- l. 136 --><p class='noindent'>For the purposes of following this guide you don’t necessarily need to do that.
|
|
However, it would be wise to run the examples within a test distribution running
|
|
on a virtual machine in order to avoid any possibility of messing up your
|
|
system.
|
|
</p><!-- l. 139 --><p class='noindent'>
|
|
</p>
|
|
<h4 class='subsectionHead' id='before-we-begin'><span class='titlemark'>1.7 </span> <a id='x1-80001.7'></a>Before We Begin</h4>
|
|
<!-- l. 141 --><p class='noindent'>Before we delve into code, there are a few issues we need to cover. Everyone’s system
|
|
is different and everyone has their own groove. Getting your first "hello world"
|
|
program to compile and load correctly can sometimes be a trick. Rest assured, after
|
|
you get over the initial hurdle of doing it for the first time, it will be smooth sailing
|
|
thereafter.
|
|
</p><!-- l. 146 --><p class='indent'>
|
|
</p><ol class='enumerate1'>
|
|
<li class='enumerate' id='x1-8002x1'>Modversioning. A module compiled for one kernel will not load if you boot
|
|
a different kernel unless you enable <code> <span class='ectt-1000'>CONFIG_MODVERSIONS</span>
|
|
</code> in the kernel. We will not go into module versioning until later in this
|
|
guide. Until we cover modversions, the examples in the guide may not
|
|
work if you are running a kernel with modversioning turned on. However,
|
|
most stock Linux distribution kernels come with it turned on. If you are
|
|
having trouble loading the modules because of versioning errors, compile
|
|
a kernel with modversioning turned off.
|
|
</li>
|
|
<li class='enumerate' id='x1-8005x2'>
|
|
<!-- l. 154 --><p class='noindent'>Using X Window System. <a id='x1-80042'></a>It is highly recommended that you extract,
|
|
compile and load all the examples this guide discusses from a console. You
|
|
should not be working on this stuff in X Window System.
|
|
</p><!-- l. 159 --><p class='noindent'>Modules can not print to the screen like <code> <span class='ectt-1000'>printf()</span>
|
|
|
|
|
|
|
|
</code> can, but they can log information and warnings, which ends up being
|
|
printed on your screen, but only on a console. If you <code> <span class='ectt-1000'>insmod</span>
|
|
</code> a module from an xterm, the information and warnings will be logged, but
|
|
only to your systemd journal. You will not see it unless you look through
|
|
your <code> <span class='ectt-1000'>journalctl</span>
|
|
</code> . See <a href='#hello-world'>4<!-- tex4ht:ref: sec:helloworld --></a> for details. To have immediate access to this information, do all
|
|
your work from the console.</p></li></ol>
|
|
<!-- l. 166 --><p class='noindent'>
|
|
</p>
|
|
<h3 class='sectionHead' id='headers'><span class='titlemark'>2 </span> <a id='x1-90002'></a>Headers</h3>
|
|
<!-- l. 168 --><p class='noindent'>Before you can build anything you’ll need to install the header files for your
|
|
kernel.
|
|
</p><!-- l. 170 --><p class='indent'> On Ubuntu/Debian:
|
|
</p>
|
|
<pre class='fancyvrb' id='fancyvrb6'><a id='x1-9004r1'></a><span class='ecrm-0500'>1</span><span class='ectt-1000'>sudo apt-get update</span>
|
|
<a id='x1-9006r2'></a><span class='ecrm-0500'>2</span><span class='ectt-1000'>apt-cache search linux-headers-</span><span id='textcolor1'><span class='tctt-1000'>`</span></span><span class='ectt-1000'>uname -r</span><span id='textcolor2'><span class='tctt-1000'>`</span></span></pre>
|
|
<!-- l. 176 --><p class='indent'> On Arch Linux:
|
|
</p>
|
|
<pre class='fancyvrb' id='fancyvrb7'><a id='x1-9009r1'></a><span class='ecrm-0500'>1</span><span class='ectt-1000'>sudo pacman -S linux-headers</span></pre>
|
|
<!-- l. 181 --><p class='indent'> This will tell you what kernel header files are available. Then for example:
|
|
</p>
|
|
<pre class='fancyvrb' id='fancyvrb8'><a id='x1-9012r1'></a><span class='ecrm-0500'>1</span><span class='ectt-1000'>sudo apt-get install kmod linux-headers-5.4.0-80-generic</span></pre>
|
|
<!-- l. 187 --><p class='noindent'>
|
|
</p>
|
|
<h3 class='sectionHead' id='examples'><span class='titlemark'>3 </span> <a id='x1-100003'></a>Examples</h3>
|
|
<!-- l. 189 --><p class='noindent'>All the examples from this document are available within the <span class='obeylines-h'><span class='verb'><span class='ectt-1000'>examples</span></span></span>
|
|
subdirectory.
|
|
</p><!-- l. 191 --><p class='indent'> If there are any compile errors then you might have a more recent kernel version
|
|
or need to install the corresponding kernel header files.
|
|
|
|
|
|
|
|
</p><!-- l. 193 --><p class='noindent'>
|
|
</p>
|
|
<h3 class='sectionHead' id='hello-world'><span class='titlemark'>4 </span> <a id='x1-110004'></a>Hello World</h3>
|
|
<!-- l. 195 --><p class='noindent'>
|
|
</p>
|
|
<h4 class='subsectionHead' id='the-simplest-module'><span class='titlemark'>4.1 </span> <a id='x1-120004.1'></a>The Simplest Module</h4>
|
|
<!-- l. 197 --><p class='noindent'>Most people learning programming start out with some sort of "<span class='ecti-1000'>hello world</span>"
|
|
example. I don’t know what happens to people who break with this tradition, but I
|
|
think it is safer not to find out. We will start with a series of hello world
|
|
programs that demonstrate the different aspects of the basics of writing a kernel
|
|
module.
|
|
</p><!-- l. 201 --><p class='indent'> Here is the simplest module possible.
|
|
</p><!-- l. 203 --><p class='indent'> Make a test directory:
|
|
</p>
|
|
<pre class='fancyvrb' id='fancyvrb9'><a id='x1-12004r1'></a><span class='ecrm-0500'>1</span><span class='ectt-1000'>mkdir -p ~/develop/kernel/hello-1</span>
|
|
<a id='x1-12006r2'></a><span class='ecrm-0500'>2</span><span class='ectt-1000'>cd ~/develop/kernel/hello-1</span></pre>
|
|
<!-- l. 209 --><p class='indent'> Paste this into your favorite editor and save it as <span class='obeylines-h'><span class='verb'><span class='ectt-1000'>hello-1.c</span></span></span>:
|
|
</p><!-- l. 1 --><p class='indent'>
|
|
</p>
|
|
<pre class='fancyvrb' id='fancyvrb10'><a id='x1-12008r1'></a><span class='ecrm-0500'>1</span><span id='textcolor3'><span class='ectt-0800'>/*</span></span>
|
|
<a id='x1-12010r2'></a><span class='ecrm-0500'>2</span><span id='textcolor4'><span class='ectt-0800'> * hello-1.c - The simplest kernel module.</span></span>
|
|
<a id='x1-12012r3'></a><span class='ecrm-0500'>3</span><span id='textcolor5'><span class='ectt-0800'> */</span></span>
|
|
<a id='x1-12014r4'></a><span class='ecrm-0500'>4</span><span id='textcolor6'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor7'><span class='ectt-0800'><linux/kernel.h> /* Needed for pr_info() */</span></span>
|
|
<a id='x1-12016r5'></a><span class='ecrm-0500'>5</span><span id='textcolor8'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor9'><span class='ectt-0800'><linux/module.h> /* Needed by all modules */</span></span>
|
|
<a id='x1-12018r6'></a><span class='ecrm-0500'>6</span>
|
|
<a id='x1-12020r7'></a><span class='ecrm-0500'>7</span><span id='textcolor10'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> init_module(</span><span id='textcolor11'><span class='ectt-0800'>void</span></span><span class='ectt-0800'>)</span>
|
|
<a id='x1-12022r8'></a><span class='ecrm-0500'>8</span><span class='ectt-0800'>{</span>
|
|
<a id='x1-12024r9'></a><span class='ecrm-0500'>9</span><span class='ectt-0800'> pr_info(</span><span id='textcolor12'><span class='ectt-0800'>"Hello world 1.</span></span><span id='textcolor13'><span class='ectt-0800'>\n</span></span><span id='textcolor14'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>);</span>
|
|
<a id='x1-12026r10'></a><span class='ecrm-0500'>10</span>
|
|
<a id='x1-12028r11'></a><span class='ecrm-0500'>11</span><span class='ectt-0800'> </span><span id='textcolor15'><span class='ectt-0800'>/* A non 0 return means init_module failed; module can</span><span class='tctt-0800'>'</span><span class='ectt-0800'>t be loaded. */</span></span>
|
|
<a id='x1-12030r12'></a><span class='ecrm-0500'>12</span><span class='ectt-0800'> </span><span id='textcolor16'><span class='ectt-0800'>return</span></span><span class='ectt-0800'> 0;</span>
|
|
<a id='x1-12032r13'></a><span class='ecrm-0500'>13</span><span class='ectt-0800'>}</span>
|
|
<a id='x1-12034r14'></a><span class='ecrm-0500'>14</span>
|
|
<a id='x1-12036r15'></a><span class='ecrm-0500'>15</span><span id='textcolor17'><span class='ectt-0800'>void</span></span><span class='ectt-0800'> cleanup_module(</span><span id='textcolor18'><span class='ectt-0800'>void</span></span><span class='ectt-0800'>)</span>
|
|
<a id='x1-12038r16'></a><span class='ecrm-0500'>16</span><span class='ectt-0800'>{</span>
|
|
<a id='x1-12040r17'></a><span class='ecrm-0500'>17</span><span class='ectt-0800'> pr_info(</span><span id='textcolor19'><span class='ectt-0800'>"Goodbye world 1.</span></span><span id='textcolor20'><span class='ectt-0800'>\n</span></span><span id='textcolor21'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>);</span>
|
|
<a id='x1-12042r18'></a><span class='ecrm-0500'>18</span><span class='ectt-0800'>}</span>
|
|
<a id='x1-12044r19'></a><span class='ecrm-0500'>19</span>
|
|
<a id='x1-12046r20'></a><span class='ecrm-0500'>20</span><span class='ectt-0800'>MODULE_LICENSE(</span><span id='textcolor22'><span class='ectt-0800'>"GPL"</span></span><span class='ectt-0800'>);</span></pre>
|
|
<!-- l. 213 --><p class='indent'> Now you will need a <span class='obeylines-h'><span class='verb'><span class='ectt-1000'>Makefile</span></span></span>. If you copy and paste this, change the indentation
|
|
to use <span class='ecti-1000'>tabs</span>, not spaces.
|
|
</p><!-- l. 1 --><p class='indent'>
|
|
</p>
|
|
<pre class='fancyvrb' id='fancyvrb11'><a id='x1-12055r1'></a><span class='ecrm-0500'>1</span><span class='ectt-0800'>obj-m += hello-1.o</span>
|
|
<a id='x1-12057r2'></a><span class='ecrm-0500'>2</span>
|
|
<a id='x1-12059r3'></a><span class='ecrm-0500'>3</span><span class='ectt-0800'>all:</span>
|
|
<a id='x1-12061r4'></a><span class='ecrm-0500'>4</span><span class='ectt-0800'> make -C /lib/modules/</span><span class='colorbox' id='colorbox23'><span class='ectt-0800'>$</span></span><span class='ectt-0800'>(shell uname -r)/build M=</span><span class='colorbox' id='colorbox24'><span class='ectt-0800'>$</span></span><span class='ectt-0800'>(PWD) modules</span>
|
|
<a id='x1-12063r5'></a><span class='ecrm-0500'>5</span>
|
|
<a id='x1-12065r6'></a><span class='ecrm-0500'>6</span><span class='ectt-0800'>clean:</span>
|
|
<a id='x1-12067r7'></a><span class='ecrm-0500'>7</span><span class='ectt-0800'> make -C /lib/modules/</span><span class='colorbox' id='colorbox25'><span class='ectt-0800'>$</span></span><span class='ectt-0800'>(shell uname -r)/build M=</span><span class='colorbox' id='colorbox26'><span class='ectt-0800'>$</span></span><span class='ectt-0800'>(PWD) clean</span></pre>
|
|
<!-- l. 225 --><p class='indent'> And finally just:
|
|
</p>
|
|
<pre class='fancyvrb' id='fancyvrb12'><a id='x1-12070r1'></a><span class='ecrm-0500'>1</span><span class='ectt-1000'>make</span></pre>
|
|
<!-- l. 230 --><p class='indent'> If all goes smoothly you should then find that you have a compiled <span class='obeylines-h'><span class='verb'><span class='ectt-1000'>hello-1.ko</span></span></span>
|
|
module. You can find info on it with the command:
|
|
</p>
|
|
<pre class='fancyvrb' id='fancyvrb13'><a id='x1-12073r1'></a><span class='ecrm-0500'>1</span><span class='ectt-1000'>sudo modinfo hello-1.ko</span></pre>
|
|
<!-- l. 236 --><p class='indent'> At this point the command:
|
|
|
|
|
|
|
|
</p>
|
|
<pre class='fancyvrb' id='fancyvrb14'><a id='x1-12076r1'></a><span class='ecrm-0500'>1</span><span class='ectt-1000'>sudo lsmod | grep hello</span></pre>
|
|
<!-- l. 241 --><p class='indent'> should return nothing. You can try loading your shiny new module with:
|
|
</p>
|
|
<pre class='fancyvrb' id='fancyvrb15'><a id='x1-12079r1'></a><span class='ecrm-0500'>1</span><span class='ectt-1000'>sudo insmod hello-1.ko</span></pre>
|
|
<!-- l. 247 --><p class='indent'> The dash character will get converted to an underscore, so when you again try:
|
|
</p>
|
|
<pre class='fancyvrb' id='fancyvrb16'><a id='x1-12082r1'></a><span class='ecrm-0500'>1</span><span class='ectt-1000'>sudo lsmod | grep hello</span></pre>
|
|
<!-- l. 252 --><p class='indent'> you should now see your loaded module. It can be removed again with:
|
|
</p>
|
|
<pre class='fancyvrb' id='fancyvrb17'><a id='x1-12085r1'></a><span class='ecrm-0500'>1</span><span class='ectt-1000'>sudo rmmod hello_1</span></pre>
|
|
<!-- l. 257 --><p class='indent'> Notice that the dash was replaced by an underscore. To see what just happened in
|
|
the logs:
|
|
</p>
|
|
<pre class='fancyvrb' id='fancyvrb18'><a id='x1-12088r1'></a><span class='ecrm-0500'>1</span><span class='ectt-1000'>sudo journalctl --since </span><span id='textcolor27'><span class='ectt-1000'>"1 hour ago"</span></span><span class='ectt-1000'> | grep kernel</span></pre>
|
|
<!-- l. 263 --><p class='indent'> You now know the basics of creating, compiling, installing and removing modules.
|
|
Now for more of a description of how this module works.
|
|
</p><!-- l. 266 --><p class='indent'> Kernel modules must have at least two functions: a "start" (initialization) function
|
|
called <code> <span class='ectt-1000'>init_module()</span>
|
|
</code> which is called when the module is <code> <span class='ectt-1000'>insmod</span>
|
|
</code>ed into the kernel, and an "end" (cleanup) function called
|
|
<code> <span class='ectt-1000'>cleanup_module()</span>
|
|
</code> which is called just before it is removed from the kernel. Actually, things have
|
|
changed starting with kernel 2.3.13. You can now use whatever name you like for the
|
|
start and end functions of a module, and you will learn how to do this in Section <a href='#hello-and-goodbye'>4.2<!-- tex4ht:ref: hello_n_goodbye --></a>.
|
|
In fact, the new method is the preferred method. However, many people still use
|
|
<code> <span class='ectt-1000'>init_module()</span>
|
|
</code> and <code> <span class='ectt-1000'>cleanup_module()</span>
|
|
</code> for their start and end functions.
|
|
</p><!-- l. 273 --><p class='indent'> Typically, <code> <span class='ectt-1000'>init_module()</span>
|
|
</code> either registers a handler for something with the kernel, or it replaces one of the kernel
|
|
|
|
|
|
|
|
functions with its own code (usually code to do something and then call the original function).
|
|
The <code> <span class='ectt-1000'>cleanup_module()</span>
|
|
</code> function is supposed to undo whatever
|
|
<code> <span class='ectt-1000'>init_module()</span>
|
|
</code> did, so the module can be unloaded safely.
|
|
</p><!-- l. 276 --><p class='indent'> Lastly, every kernel module needs to include <span class='obeylines-h'><span class='verb'><span class='ectt-1000'><linux/module.h></span></span></span>. We
|
|
needed to include <span class='obeylines-h'><span class='verb'><span class='ectt-1000'><linux/kernel.h></span></span></span> only for the macro expansion for the
|
|
<code> <span class='ectt-1000'>pr_alert()</span>
|
|
</code> log level, which you’ll learn about in Section <a href='#x1-121002'>2<!-- tex4ht:ref: sec:printk --></a>.
|
|
</p><!-- l. 280 --><p class='indent'>
|
|
</p><ol class='enumerate1'>
|
|
<li class='enumerate' id='x1-12099x1'>A point about coding style. Another thing which may not be immediately
|
|
obvious to anyone getting started with kernel programming is that
|
|
indentation within your code should be using <span class='ecbx-1000'>tabs </span>and <span class='ecbx-1000'>not spaces</span>. It is
|
|
one of the coding conventions of the kernel. You may not like it, but you’ll
|
|
need to get used to it if you ever submit a patch upstream.
|
|
</li>
|
|
<li class='enumerate' id='x1-12101x2'>Introducing print macros. <a id='x1-121002'></a>In the beginning there was <code> <span class='ectt-1000'>printk</span>
|
|
</code>, usually followed by a priority such as <code> <span class='ectt-1000'>KERN_INFO</span>
|
|
</code> or <code> <span class='ectt-1000'>KERN_DEBUG</span>
|
|
</code>. More recently this can also be expressed in abbreviated form using a set of
|
|
print macros, such as <code> <span class='ectt-1000'>pr_info</span>
|
|
</code> and <code> <span class='ectt-1000'>pr_debug</span>
|
|
</code>. This just saves some mindless keyboard bashing and looks a bit neater.
|
|
They can be found within <a href='https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/tree/include/linux/printk.h'>include/linux/printk.h</a>. Take time to read through
|
|
the available priority macros.
|
|
</li>
|
|
<li class='enumerate' id='x1-12108x3'>
|
|
<!-- l. 294 --><p class='noindent'>About Compiling. Kernel modules need to be compiled a bit differently
|
|
from regular userspace apps. Former kernel versions required us to
|
|
care much about these settings, which are usually stored in Makefiles.
|
|
Although hierarchically organized, many redundant settings accumulated
|
|
in sublevel Makefiles and made them large and rather difficult to maintain.
|
|
|
|
|
|
|
|
Fortunately, there is a new way of doing these things, called kbuild, and
|
|
the build process for external loadable modules is now fully integrated into
|
|
the standard kernel build mechanism. To learn more on how to compile
|
|
modules which are not part of the official kernel (such as all the examples
|
|
you will find in this guide), see file <a href='https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/tree/Documentation/kbuild/modules.rst'>Documentation/kbuild/modules.rst</a>.
|
|
</p><!-- l. 301 --><p class='noindent'>Additional details about Makefiles for kernel modules are available in
|
|
<a href='https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/tree/Documentation/kbuild/makefiles.rst'>Documentation/kbuild/makefiles.rst</a>. Be sure to read this and the related
|
|
files before starting to hack Makefiles. It will probably save you lots of
|
|
work.
|
|
</p><!-- l. 303 --><p class='noindent'>
|
|
</p><blockquote class='quote'>
|
|
<!-- l. 304 --><p class='noindent'>Here is another exercise for the reader. See that comment above
|
|
the return statement in <code> <span class='ectt-1000'>init_module()</span>
|
|
</code>? Change the return value to something negative, recompile and
|
|
load the module again. What happens?</p></blockquote>
|
|
</li></ol>
|
|
<!-- l. 311 --><p class='noindent'>
|
|
</p>
|
|
<h4 class='subsectionHead' id='hello-and-goodbye'><span class='titlemark'>4.2 </span> <a id='x1-130004.2'></a>Hello and Goodbye</h4>
|
|
<!-- l. 313 --><p class='noindent'>In early kernel versions you had to use the
|
|
<code> <span class='ectt-1000'>init_module</span>
|
|
</code> and <code> <span class='ectt-1000'>cleanup_module</span>
|
|
</code> functions, as in the first hello world example, but these days you can name those anything you
|
|
want by using the <code> <span class='ectt-1000'>module_init</span>
|
|
</code> and <code> <span class='ectt-1000'>module_exit</span>
|
|
</code> macros. These macros are defined in <a href='https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/tree/include/linux/init.h'>include/linux/init.h</a>. The only requirement is
|
|
that your init and cleanup functions must be defined before calling the those
|
|
macros, otherwise you’ll get compilation errors. Here is an example of this
|
|
technique:
|
|
</p><!-- l. 1 --><p class='indent'>
|
|
</p>
|
|
<pre class='fancyvrb' id='fancyvrb19'><a id='x1-13006r1'></a><span class='ecrm-0500'>1</span><span id='textcolor28'><span class='ectt-0800'>/*</span></span>
|
|
<a id='x1-13008r2'></a><span class='ecrm-0500'>2</span><span id='textcolor29'><span class='ectt-0800'> * hello-2.c - Demonstrating the module_init() and module_exit() macros.</span></span>
|
|
<a id='x1-13010r3'></a><span class='ecrm-0500'>3</span><span id='textcolor30'><span class='ectt-0800'> * This is preferred over using init_module() and cleanup_module().</span></span>
|
|
<a id='x1-13012r4'></a><span class='ecrm-0500'>4</span><span id='textcolor31'><span class='ectt-0800'> */</span></span>
|
|
<a id='x1-13014r5'></a><span class='ecrm-0500'>5</span><span id='textcolor32'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor33'><span class='ectt-0800'><linux/init.h> /* Needed for the macros */</span></span>
|
|
<a id='x1-13016r6'></a><span class='ecrm-0500'>6</span><span id='textcolor34'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor35'><span class='ectt-0800'><linux/kernel.h> /* Needed for pr_info() */</span></span>
|
|
<a id='x1-13018r7'></a><span class='ecrm-0500'>7</span><span id='textcolor36'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor37'><span class='ectt-0800'><linux/module.h> /* Needed by all modules */</span></span>
|
|
<a id='x1-13020r8'></a><span class='ecrm-0500'>8</span>
|
|
<a id='x1-13022r9'></a><span class='ecrm-0500'>9</span><span id='textcolor38'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor39'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> __init hello_2_init(</span><span id='textcolor40'><span class='ectt-0800'>void</span></span><span class='ectt-0800'>)</span>
|
|
<a id='x1-13024r10'></a><span class='ecrm-0500'>10</span><span class='ectt-0800'>{</span>
|
|
<a id='x1-13026r11'></a><span class='ecrm-0500'>11</span><span class='ectt-0800'> pr_info(</span><span id='textcolor41'><span class='ectt-0800'>"Hello, world 2</span></span><span id='textcolor42'><span class='ectt-0800'>\n</span></span><span id='textcolor43'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>);</span>
|
|
<a id='x1-13028r12'></a><span class='ecrm-0500'>12</span><span class='ectt-0800'> </span><span id='textcolor44'><span class='ectt-0800'>return</span></span><span class='ectt-0800'> 0;</span>
|
|
<a id='x1-13030r13'></a><span class='ecrm-0500'>13</span><span class='ectt-0800'>}</span>
|
|
<a id='x1-13032r14'></a><span class='ecrm-0500'>14</span>
|
|
<a id='x1-13034r15'></a><span class='ecrm-0500'>15</span><span id='textcolor45'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor46'><span class='ectt-0800'>void</span></span><span class='ectt-0800'> __exit hello_2_exit(</span><span id='textcolor47'><span class='ectt-0800'>void</span></span><span class='ectt-0800'>)</span>
|
|
<a id='x1-13036r16'></a><span class='ecrm-0500'>16</span><span class='ectt-0800'>{</span>
|
|
<a id='x1-13038r17'></a><span class='ecrm-0500'>17</span><span class='ectt-0800'> pr_info(</span><span id='textcolor48'><span class='ectt-0800'>"Goodbye, world 2</span></span><span id='textcolor49'><span class='ectt-0800'>\n</span></span><span id='textcolor50'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>);</span>
|
|
<a id='x1-13040r18'></a><span class='ecrm-0500'>18</span><span class='ectt-0800'>}</span>
|
|
<a id='x1-13042r19'></a><span class='ecrm-0500'>19</span>
|
|
<a id='x1-13044r20'></a><span class='ecrm-0500'>20</span><span class='ectt-0800'>module_init(hello_2_init);</span>
|
|
<a id='x1-13046r21'></a><span class='ecrm-0500'>21</span><span class='ectt-0800'>module_exit(hello_2_exit);</span>
|
|
<a id='x1-13048r22'></a><span class='ecrm-0500'>22</span>
|
|
<a id='x1-13050r23'></a><span class='ecrm-0500'>23</span><span class='ectt-0800'>MODULE_LICENSE(</span><span id='textcolor51'><span class='ectt-0800'>"GPL"</span></span><span class='ectt-0800'>);</span></pre>
|
|
<!-- l. 320 --><p class='indent'> So now we have two real kernel modules under our belt. Adding another module
|
|
is as simple as this:
|
|
</p><!-- l. 1 --><p class='indent'>
|
|
</p>
|
|
<pre class='fancyvrb' id='fancyvrb20'><a id='x1-13060r1'></a><span class='ecrm-0500'>1</span><span class='ectt-0800'>obj-m += hello-1.o</span>
|
|
<a id='x1-13062r2'></a><span class='ecrm-0500'>2</span><span class='ectt-0800'>obj-m += hello-2.o</span>
|
|
<a id='x1-13064r3'></a><span class='ecrm-0500'>3</span>
|
|
<a id='x1-13066r4'></a><span class='ecrm-0500'>4</span><span class='ectt-0800'>all:</span>
|
|
<a id='x1-13068r5'></a><span class='ecrm-0500'>5</span><span class='ectt-0800'> make -C /lib/modules/</span><span class='colorbox' id='colorbox52'><span class='ectt-0800'>$</span></span><span class='ectt-0800'>(shell uname -r)/build M=</span><span class='colorbox' id='colorbox53'><span class='ectt-0800'>$</span></span><span class='ectt-0800'>(PWD) modules</span>
|
|
<a id='x1-13070r6'></a><span class='ecrm-0500'>6</span>
|
|
<a id='x1-13072r7'></a><span class='ecrm-0500'>7</span><span class='ectt-0800'>clean:</span>
|
|
<a id='x1-13074r8'></a><span class='ecrm-0500'>8</span><span class='ectt-0800'> make -C /lib/modules/</span><span class='colorbox' id='colorbox54'><span class='ectt-0800'>$</span></span><span class='ectt-0800'>(shell uname -r)/build M=</span><span class='colorbox' id='colorbox55'><span class='ectt-0800'>$</span></span><span class='ectt-0800'>(PWD) clean</span></pre>
|
|
|
|
|
|
|
|
<!-- l. 333 --><p class='indent'> Now have a look at <a href='https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/tree/drivers/char/Makefile'>drivers/char/Makefile</a> for a real world example. As you can
|
|
see, some things get hardwired into the kernel (<span class='obeylines-h'><span class='verb'><span class='ectt-1000'>obj-y</span></span></span>) but where are all those <span class='obeylines-h'><span class='verb'><span class='ectt-1000'>obj-m</span></span></span>
|
|
gone? Those familiar with shell scripts will easily be able to spot them. For those not,
|
|
the <span class='obeylines-h'><span class='verb'><span class='ectt-1000'>obj-$(CONFIG_FOO)</span></span></span> entries you see everywhere expand into <span class='obeylines-h'><span class='verb'><span class='ectt-1000'>obj-y</span></span></span> or <span class='obeylines-h'><span class='verb'><span class='ectt-1000'>obj-m</span></span></span>,
|
|
depending on whether the <span class='obeylines-h'><span class='verb'><span class='ectt-1000'>CONFIG_FOO</span></span></span> variable has been set to <span class='obeylines-h'><span class='verb'><span class='ectt-1000'>y</span></span></span> or <span class='obeylines-h'><span class='verb'><span class='ectt-1000'>m</span></span></span>. While we are
|
|
at it, those were exactly the kind of variables that you have set in the <span class='obeylines-h'><span class='verb'><span class='ectt-1000'>.config</span></span></span> file in
|
|
the top-level directory of Linux kernel source tree, the last time when you said
|
|
<code> <span class='ectt-1000'>make menuconfig</span>
|
|
</code> or something like that.
|
|
</p><!-- l. 339 --><p class='noindent'>
|
|
</p>
|
|
<h4 class='subsectionHead' id='the-init-and-exit-macros'><span class='titlemark'>4.3 </span> <a id='x1-140004.3'></a>The __init and __exit Macros</h4>
|
|
<!-- l. 341 --><p class='noindent'>The <code> <span class='ectt-1000'>__init</span>
|
|
</code> macro causes the init function to be discarded and its memory freed once the init
|
|
function finishes for built-in drivers, but not loadable modules. If you think about
|
|
when the init function is invoked, this makes perfect sense.
|
|
</p><!-- l. 344 --><p class='indent'> There is also an <code> <span class='ectt-1000'>__initdata</span>
|
|
</code> which works similarly to <code> <span class='ectt-1000'>__init</span>
|
|
</code> but for init variables rather than functions.
|
|
</p><!-- l. 346 --><p class='indent'> The <code> <span class='ectt-1000'>__exit</span>
|
|
</code> macro causes the omission of the function when the module is built into the kernel, and
|
|
like <code> <span class='ectt-1000'>__init</span>
|
|
</code>, has no effect for loadable modules. Again, if you consider when the cleanup function
|
|
runs, this makes complete sense; built-in drivers do not need a cleanup function,
|
|
while loadable modules do.
|
|
</p><!-- l. 349 --><p class='indent'> These macros are defined in <a href='https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/tree/include/linux/init.h'>include/linux/init.h</a> and serve to free up kernel
|
|
memory. When you boot your kernel and see something like Freeing unused kernel
|
|
memory: 236k freed, this is precisely what the kernel is freeing.
|
|
</p><!-- l. 1 --><p class='indent'>
|
|
</p>
|
|
<pre class='fancyvrb' id='fancyvrb21'><a id='x1-14007r1'></a><span class='ecrm-0500'>1</span><span id='textcolor56'><span class='ectt-0800'>/*</span></span>
|
|
<a id='x1-14009r2'></a><span class='ecrm-0500'>2</span><span id='textcolor57'><span class='ectt-0800'> * hello-3.c - Illustrating the __init, __initdata and __exit macros.</span></span>
|
|
<a id='x1-14011r3'></a><span class='ecrm-0500'>3</span><span id='textcolor58'><span class='ectt-0800'> */</span></span>
|
|
<a id='x1-14013r4'></a><span class='ecrm-0500'>4</span><span id='textcolor59'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor60'><span class='ectt-0800'><linux/init.h> /* Needed for the macros */</span></span>
|
|
<a id='x1-14015r5'></a><span class='ecrm-0500'>5</span><span id='textcolor61'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor62'><span class='ectt-0800'><linux/kernel.h> /* Needed for pr_info() */</span></span>
|
|
<a id='x1-14017r6'></a><span class='ecrm-0500'>6</span><span id='textcolor63'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor64'><span class='ectt-0800'><linux/module.h> /* Needed by all modules */</span></span>
|
|
<a id='x1-14019r7'></a><span class='ecrm-0500'>7</span>
|
|
<a id='x1-14021r8'></a><span class='ecrm-0500'>8</span><span id='textcolor65'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor66'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> hello3_data __initdata = 3;</span>
|
|
<a id='x1-14023r9'></a><span class='ecrm-0500'>9</span>
|
|
<a id='x1-14025r10'></a><span class='ecrm-0500'>10</span><span id='textcolor67'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor68'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> __init hello_3_init(</span><span id='textcolor69'><span class='ectt-0800'>void</span></span><span class='ectt-0800'>)</span>
|
|
<a id='x1-14027r11'></a><span class='ecrm-0500'>11</span><span class='ectt-0800'>{</span>
|
|
<a id='x1-14029r12'></a><span class='ecrm-0500'>12</span><span class='ectt-0800'> pr_info(</span><span id='textcolor70'><span class='ectt-0800'>"Hello, world %d</span></span><span id='textcolor71'><span class='ectt-0800'>\n</span></span><span id='textcolor72'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>, hello3_data);</span>
|
|
<a id='x1-14031r13'></a><span class='ecrm-0500'>13</span><span class='ectt-0800'> </span><span id='textcolor73'><span class='ectt-0800'>return</span></span><span class='ectt-0800'> 0;</span>
|
|
<a id='x1-14033r14'></a><span class='ecrm-0500'>14</span><span class='ectt-0800'>}</span>
|
|
<a id='x1-14035r15'></a><span class='ecrm-0500'>15</span>
|
|
<a id='x1-14037r16'></a><span class='ecrm-0500'>16</span><span id='textcolor74'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor75'><span class='ectt-0800'>void</span></span><span class='ectt-0800'> __exit hello_3_exit(</span><span id='textcolor76'><span class='ectt-0800'>void</span></span><span class='ectt-0800'>)</span>
|
|
<a id='x1-14039r17'></a><span class='ecrm-0500'>17</span><span class='ectt-0800'>{</span>
|
|
<a id='x1-14041r18'></a><span class='ecrm-0500'>18</span><span class='ectt-0800'> pr_info(</span><span id='textcolor77'><span class='ectt-0800'>"Goodbye, world 3</span></span><span id='textcolor78'><span class='ectt-0800'>\n</span></span><span id='textcolor79'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>);</span>
|
|
<a id='x1-14043r19'></a><span class='ecrm-0500'>19</span><span class='ectt-0800'>}</span>
|
|
<a id='x1-14045r20'></a><span class='ecrm-0500'>20</span>
|
|
<a id='x1-14047r21'></a><span class='ecrm-0500'>21</span><span class='ectt-0800'>module_init(hello_3_init);</span>
|
|
<a id='x1-14049r22'></a><span class='ecrm-0500'>22</span><span class='ectt-0800'>module_exit(hello_3_exit);</span>
|
|
<a id='x1-14051r23'></a><span class='ecrm-0500'>23</span>
|
|
<a id='x1-14053r24'></a><span class='ecrm-0500'>24</span><span class='ectt-0800'>MODULE_LICENSE(</span><span id='textcolor80'><span class='ectt-0800'>"GPL"</span></span><span class='ectt-0800'>);</span></pre>
|
|
<!-- l. 354 --><p class='noindent'>
|
|
</p>
|
|
<h4 class='subsectionHead' id='licensing-and-module-documentation'><span class='titlemark'>4.4 </span> <a id='x1-150004.4'></a>Licensing and Module Documentation</h4>
|
|
<!-- l. 356 --><p class='noindent'>Honestly, who loads or even cares about proprietary modules? If you do then you
|
|
might have seen something like this:
|
|
|
|
|
|
|
|
</p>
|
|
<pre class='verbatim' id='verbatim-1'>
|
|
$ sudo insmod xxxxxx.ko
|
|
loading out-of-tree module taints kernel.
|
|
module license 'unspecified' taints kernel.
|
|
</pre>
|
|
<!-- l. 362 --><p class='nopar'>
|
|
</p><!-- l. 364 --><p class='indent'> You can use a few macros to indicate the license for your module. Some examples
|
|
are "GPL", "GPL v2", "GPL and additional rights", "Dual BSD/GPL", "Dual
|
|
MIT/GPL", "Dual MPL/GPL" and "Proprietary". They are defined within
|
|
<a href='https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/tree/include/linux/module.h'>include/linux/module.h</a>.
|
|
</p><!-- l. 368 --><p class='indent'> To reference what license you’re using a macro is available called
|
|
<code> <span class='ectt-1000'>MODULE_LICENSE</span>
|
|
</code>. This and a few other macros describing the module are illustrated in the below
|
|
example.
|
|
</p><!-- l. 1 --><p class='indent'>
|
|
</p>
|
|
<pre class='fancyvrb' id='fancyvrb22'><a id='x1-15003r1'></a><span class='ecrm-0500'>1</span><span id='textcolor81'><span class='ectt-0800'>/*</span></span>
|
|
<a id='x1-15005r2'></a><span class='ecrm-0500'>2</span><span id='textcolor82'><span class='ectt-0800'> * hello-4.c - Demonstrates module documentation.</span></span>
|
|
<a id='x1-15007r3'></a><span class='ecrm-0500'>3</span><span id='textcolor83'><span class='ectt-0800'> */</span></span>
|
|
<a id='x1-15009r4'></a><span class='ecrm-0500'>4</span><span id='textcolor84'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor85'><span class='ectt-0800'><linux/init.h> /* Needed for the macros */</span></span>
|
|
<a id='x1-15011r5'></a><span class='ecrm-0500'>5</span><span id='textcolor86'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor87'><span class='ectt-0800'><linux/kernel.h> /* Needed for pr_info() */</span></span>
|
|
<a id='x1-15013r6'></a><span class='ecrm-0500'>6</span><span id='textcolor88'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor89'><span class='ectt-0800'><linux/module.h> /* Needed by all modules */</span></span>
|
|
<a id='x1-15015r7'></a><span class='ecrm-0500'>7</span>
|
|
<a id='x1-15017r8'></a><span class='ecrm-0500'>8</span><span class='ectt-0800'>MODULE_LICENSE(</span><span id='textcolor90'><span class='ectt-0800'>"GPL"</span></span><span class='ectt-0800'>);</span>
|
|
<a id='x1-15019r9'></a><span class='ecrm-0500'>9</span><span class='ectt-0800'>MODULE_AUTHOR(</span><span id='textcolor91'><span class='ectt-0800'>"LKMPG"</span></span><span class='ectt-0800'>);</span>
|
|
<a id='x1-15021r10'></a><span class='ecrm-0500'>10</span><span class='ectt-0800'>MODULE_DESCRIPTION(</span><span id='textcolor92'><span class='ectt-0800'>"A sample driver"</span></span><span class='ectt-0800'>);</span>
|
|
<a id='x1-15023r11'></a><span class='ecrm-0500'>11</span>
|
|
<a id='x1-15025r12'></a><span class='ecrm-0500'>12</span><span id='textcolor93'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor94'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> __init init_hello_4(</span><span id='textcolor95'><span class='ectt-0800'>void</span></span><span class='ectt-0800'>)</span>
|
|
<a id='x1-15027r13'></a><span class='ecrm-0500'>13</span><span class='ectt-0800'>{</span>
|
|
<a id='x1-15029r14'></a><span class='ecrm-0500'>14</span><span class='ectt-0800'> pr_info(</span><span id='textcolor96'><span class='ectt-0800'>"Hello, world 4</span></span><span id='textcolor97'><span class='ectt-0800'>\n</span></span><span id='textcolor98'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>);</span>
|
|
<a id='x1-15031r15'></a><span class='ecrm-0500'>15</span><span class='ectt-0800'> </span><span id='textcolor99'><span class='ectt-0800'>return</span></span><span class='ectt-0800'> 0;</span>
|
|
<a id='x1-15033r16'></a><span class='ecrm-0500'>16</span><span class='ectt-0800'>}</span>
|
|
<a id='x1-15035r17'></a><span class='ecrm-0500'>17</span>
|
|
<a id='x1-15037r18'></a><span class='ecrm-0500'>18</span><span id='textcolor100'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor101'><span class='ectt-0800'>void</span></span><span class='ectt-0800'> __exit cleanup_hello_4(</span><span id='textcolor102'><span class='ectt-0800'>void</span></span><span class='ectt-0800'>)</span>
|
|
<a id='x1-15039r19'></a><span class='ecrm-0500'>19</span><span class='ectt-0800'>{</span>
|
|
<a id='x1-15041r20'></a><span class='ecrm-0500'>20</span><span class='ectt-0800'> pr_info(</span><span id='textcolor103'><span class='ectt-0800'>"Goodbye, world 4</span></span><span id='textcolor104'><span class='ectt-0800'>\n</span></span><span id='textcolor105'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>);</span>
|
|
<a id='x1-15043r21'></a><span class='ecrm-0500'>21</span><span class='ectt-0800'>}</span>
|
|
<a id='x1-15045r22'></a><span class='ecrm-0500'>22</span>
|
|
<a id='x1-15047r23'></a><span class='ecrm-0500'>23</span><span class='ectt-0800'>module_init(init_hello_4);</span>
|
|
<a id='x1-15049r24'></a><span class='ecrm-0500'>24</span><span class='ectt-0800'>module_exit(cleanup_hello_4);</span></pre>
|
|
<!-- l. 373 --><p class='noindent'>
|
|
</p>
|
|
<h4 class='subsectionHead' id='passing-command-line-arguments-to-a-module'><span class='titlemark'>4.5 </span> <a id='x1-160004.5'></a>Passing Command Line Arguments to a Module</h4>
|
|
<!-- l. 375 --><p class='noindent'>Modules can take command line arguments, but not with the argc/argv you might be
|
|
used to.
|
|
</p><!-- l. 377 --><p class='indent'> To allow arguments to be passed to your module, declare the variables that will
|
|
take the values of the command line arguments as global and then use the
|
|
<code> <span class='ectt-1000'>module_param()</span>
|
|
</code> macro, (defined in <a href='https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/tree/include/linux/moduleparam.h'>include/linux/moduleparam.h</a>) to set the mechanism up. At runtime,
|
|
<code> <span class='ectt-1000'>insmod</span>
|
|
</code> will fill the variables with any command line arguments that are given, like
|
|
<code> <span class='ectt-1000'>insmod mymodule.ko myvariable=5</span>
|
|
</code>. The variable declarations and macros should be placed at the beginning of the
|
|
module for clarity. The example code should clear up my admittedly lousy
|
|
explanation.
|
|
</p><!-- l. 382 --><p class='indent'> The <code> <span class='ectt-1000'>module_param()</span>
|
|
</code> macro takes 3 arguments: the name of the variable, its type and
|
|
permissions for the corresponding file in sysfs. Integer types can be signed
|
|
as usual or unsigned. If you’d like to use arrays of integers or strings see
|
|
<code> <span class='ectt-1000'>module_param_array()</span>
|
|
</code> and <code> <span class='ectt-1000'>module_param_string()</span>
|
|
</code>.
|
|
</p><!-- l. 1 --><p class='indent'>
|
|
|
|
|
|
|
|
</p>
|
|
<pre class='fancyvrb' id='fancyvrb23'><a id='x1-16010r1'></a><span class='ecrm-0500'>1</span><span id='textcolor106'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> myint = 3;</span>
|
|
<a id='x1-16012r2'></a><span class='ecrm-0500'>2</span><span class='ectt-0800'>module_param(myint, </span><span id='textcolor107'><span class='ectt-0800'>int</span></span><span class='ectt-0800'>, 0);</span></pre>
|
|
<!-- l. 390 --><p class='indent'> Arrays are supported too, but things are a bit different now than they were in the
|
|
olden days. To keep track of the number of parameters you need to pass a pointer to
|
|
a count variable as third parameter. At your option, you could also ignore the count and
|
|
pass <code> <span class='ectt-1000'>NULL</span>
|
|
</code> instead. We show both possibilities here:
|
|
</p><!-- l. 1 --><p class='indent'>
|
|
</p>
|
|
<pre class='fancyvrb' id='fancyvrb24'><a id='x1-16021r1'></a><span class='ecrm-0500'>1</span><span id='textcolor108'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> myintarray[2];</span>
|
|
<a id='x1-16023r2'></a><span class='ecrm-0500'>2</span><span class='ectt-0800'>module_param_array(myintarray, </span><span id='textcolor109'><span class='ectt-0800'>int</span></span><span class='ectt-0800'>, NULL, 0); </span><span id='textcolor110'><span class='ectt-0800'>/* not interested in count */</span></span>
|
|
<a id='x1-16025r3'></a><span class='ecrm-0500'>3</span>
|
|
<a id='x1-16027r4'></a><span class='ecrm-0500'>4</span><span id='textcolor111'><span class='ectt-0800'>short</span></span><span class='ectt-0800'> myshortarray[4];</span>
|
|
<a id='x1-16029r5'></a><span class='ecrm-0500'>5</span><span id='textcolor112'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> count;</span>
|
|
<a id='x1-16031r6'></a><span class='ecrm-0500'>6</span><span class='ectt-0800'>module_param_array(myshortarray, </span><span id='textcolor113'><span class='ectt-0800'>short</span></span><span class='ectt-0800'>, &count, 0); </span><span id='textcolor114'><span class='ectt-0800'>/* put count into "count" variable */</span></span></pre>
|
|
<!-- l. 403 --><p class='indent'> A good use for this is to have the module variable’s default values set, like an port
|
|
or IO address. If the variables contain the default values, then perform autodetection
|
|
(explained elsewhere). Otherwise, keep the current value. This will be made clear
|
|
later on.
|
|
</p><!-- l. 407 --><p class='indent'> Lastly, there is a macro function, <code> <span class='ectt-1000'>MODULE_PARM_DESC()</span>
|
|
</code>, that is used to document arguments that the module can take. It takes two
|
|
parameters: a variable name and a free form string describing that variable.
|
|
</p><!-- l. 1 --><p class='indent'>
|
|
</p>
|
|
<pre class='fancyvrb' id='fancyvrb25'><a id='x1-16034r1'></a><span class='ecrm-0500'>1</span><span id='textcolor115'><span class='ectt-0800'>/*</span></span>
|
|
<a id='x1-16036r2'></a><span class='ecrm-0500'>2</span><span id='textcolor116'><span class='ectt-0800'> * hello-5.c - Demonstrates command line argument passing to a module.</span></span>
|
|
<a id='x1-16038r3'></a><span class='ecrm-0500'>3</span><span id='textcolor117'><span class='ectt-0800'> */</span></span>
|
|
<a id='x1-16040r4'></a><span class='ecrm-0500'>4</span><span id='textcolor118'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor119'><span class='ectt-0800'><linux/init.h></span></span>
|
|
<a id='x1-16042r5'></a><span class='ecrm-0500'>5</span><span id='textcolor120'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor121'><span class='ectt-0800'><linux/kernel.h></span></span>
|
|
<a id='x1-16044r6'></a><span class='ecrm-0500'>6</span><span id='textcolor122'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor123'><span class='ectt-0800'><linux/module.h></span></span>
|
|
<a id='x1-16046r7'></a><span class='ecrm-0500'>7</span><span id='textcolor124'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor125'><span class='ectt-0800'><linux/moduleparam.h></span></span>
|
|
<a id='x1-16048r8'></a><span class='ecrm-0500'>8</span><span id='textcolor126'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor127'><span class='ectt-0800'><linux/stat.h></span></span>
|
|
<a id='x1-16050r9'></a><span class='ecrm-0500'>9</span>
|
|
<a id='x1-16052r10'></a><span class='ecrm-0500'>10</span><span class='ectt-0800'>MODULE_LICENSE(</span><span id='textcolor128'><span class='ectt-0800'>"GPL"</span></span><span class='ectt-0800'>);</span>
|
|
<a id='x1-16054r11'></a><span class='ecrm-0500'>11</span>
|
|
<a id='x1-16056r12'></a><span class='ecrm-0500'>12</span><span id='textcolor129'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor130'><span class='ectt-0800'>short</span></span><span class='ectt-0800'> </span><span id='textcolor131'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> myshort = 1;</span>
|
|
<a id='x1-16058r13'></a><span class='ecrm-0500'>13</span><span id='textcolor132'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor133'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> myint = 420;</span>
|
|
<a id='x1-16060r14'></a><span class='ecrm-0500'>14</span><span id='textcolor134'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor135'><span class='ectt-0800'>long</span></span><span class='ectt-0800'> </span><span id='textcolor136'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> mylong = 9999;</span>
|
|
<a id='x1-16062r15'></a><span class='ecrm-0500'>15</span><span id='textcolor137'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor138'><span class='ectt-0800'>char</span></span><span class='ectt-0800'> *mystring = </span><span id='textcolor139'><span class='ectt-0800'>"blah"</span></span><span class='ectt-0800'>;</span>
|
|
<a id='x1-16064r16'></a><span class='ecrm-0500'>16</span><span id='textcolor140'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor141'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> myintarray[2] = { 420, 420 };</span>
|
|
<a id='x1-16066r17'></a><span class='ecrm-0500'>17</span><span id='textcolor142'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor143'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> arr_argc = 0;</span>
|
|
<a id='x1-16068r18'></a><span class='ecrm-0500'>18</span>
|
|
<a id='x1-16070r19'></a><span class='ecrm-0500'>19</span><span id='textcolor144'><span class='ectt-0800'>/* module_param(foo, int, 0000)</span></span>
|
|
<a id='x1-16072r20'></a><span class='ecrm-0500'>20</span><span id='textcolor145'><span class='ectt-0800'> * The first param is the parameters name.</span></span>
|
|
<a id='x1-16074r21'></a><span class='ecrm-0500'>21</span><span id='textcolor146'><span class='ectt-0800'> * The second param is its data type.</span></span>
|
|
<a id='x1-16076r22'></a><span class='ecrm-0500'>22</span><span id='textcolor147'><span class='ectt-0800'> * The final argument is the permissions bits,</span></span>
|
|
<a id='x1-16078r23'></a><span class='ecrm-0500'>23</span><span id='textcolor148'><span class='ectt-0800'> * for exposing parameters in sysfs (if non-zero) at a later stage.</span></span>
|
|
<a id='x1-16080r24'></a><span class='ecrm-0500'>24</span><span id='textcolor149'><span class='ectt-0800'> */</span></span>
|
|
<a id='x1-16082r25'></a><span class='ecrm-0500'>25</span><span class='ectt-0800'>module_param(myshort, </span><span id='textcolor150'><span class='ectt-0800'>short</span></span><span class='ectt-0800'>, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP);</span>
|
|
<a id='x1-16084r26'></a><span class='ecrm-0500'>26</span><span class='ectt-0800'>MODULE_PARM_DESC(myshort, </span><span id='textcolor151'><span class='ectt-0800'>"A short integer"</span></span><span class='ectt-0800'>);</span>
|
|
<a id='x1-16086r27'></a><span class='ecrm-0500'>27</span><span class='ectt-0800'>module_param(myint, </span><span id='textcolor152'><span class='ectt-0800'>int</span></span><span class='ectt-0800'>, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);</span>
|
|
<a id='x1-16088r28'></a><span class='ecrm-0500'>28</span><span class='ectt-0800'>MODULE_PARM_DESC(myint, </span><span id='textcolor153'><span class='ectt-0800'>"An integer"</span></span><span class='ectt-0800'>);</span>
|
|
<a id='x1-16090r29'></a><span class='ecrm-0500'>29</span><span class='ectt-0800'>module_param(mylong, </span><span id='textcolor154'><span class='ectt-0800'>long</span></span><span class='ectt-0800'>, S_IRUSR);</span>
|
|
<a id='x1-16092r30'></a><span class='ecrm-0500'>30</span><span class='ectt-0800'>MODULE_PARM_DESC(mylong, </span><span id='textcolor155'><span class='ectt-0800'>"A long integer"</span></span><span class='ectt-0800'>);</span>
|
|
<a id='x1-16094r31'></a><span class='ecrm-0500'>31</span><span class='ectt-0800'>module_param(mystring, charp, 0000);</span>
|
|
<a id='x1-16096r32'></a><span class='ecrm-0500'>32</span><span class='ectt-0800'>MODULE_PARM_DESC(mystring, </span><span id='textcolor156'><span class='ectt-0800'>"A character string"</span></span><span class='ectt-0800'>);</span>
|
|
<a id='x1-16098r33'></a><span class='ecrm-0500'>33</span>
|
|
<a id='x1-16100r34'></a><span class='ecrm-0500'>34</span><span id='textcolor157'><span class='ectt-0800'>/* module_param_array(name, type, num, perm);</span></span>
|
|
<a id='x1-16102r35'></a><span class='ecrm-0500'>35</span><span id='textcolor158'><span class='ectt-0800'> * The first param is the parameter</span><span class='tctt-0800'>'</span><span class='ectt-0800'>s (in this case the array</span><span class='tctt-0800'>'</span><span class='ectt-0800'>s) name.</span></span>
|
|
<a id='x1-16104r36'></a><span class='ecrm-0500'>36</span><span id='textcolor159'><span class='ectt-0800'> * The second param is the data type of the elements of the array.</span></span>
|
|
<a id='x1-16106r37'></a><span class='ecrm-0500'>37</span><span id='textcolor160'><span class='ectt-0800'> * The third argument is a pointer to the variable that will store the number.</span></span>
|
|
<a id='x1-16108r38'></a><span class='ecrm-0500'>38</span><span id='textcolor161'><span class='ectt-0800'> * of elements of the array initialized by the user at module loading time.</span></span>
|
|
<a id='x1-16110r39'></a><span class='ecrm-0500'>39</span><span id='textcolor162'><span class='ectt-0800'> * The fourth argument is the permission bits.</span></span>
|
|
<a id='x1-16112r40'></a><span class='ecrm-0500'>40</span><span id='textcolor163'><span class='ectt-0800'> */</span></span>
|
|
<a id='x1-16114r41'></a><span class='ecrm-0500'>41</span><span class='ectt-0800'>module_param_array(myintarray, </span><span id='textcolor164'><span class='ectt-0800'>int</span></span><span class='ectt-0800'>, &arr_argc, 0000);</span>
|
|
<a id='x1-16116r42'></a><span class='ecrm-0500'>42</span><span class='ectt-0800'>MODULE_PARM_DESC(myintarray, </span><span id='textcolor165'><span class='ectt-0800'>"An array of integers"</span></span><span class='ectt-0800'>);</span>
|
|
<a id='x1-16118r43'></a><span class='ecrm-0500'>43</span>
|
|
<a id='x1-16120r44'></a><span class='ecrm-0500'>44</span><span id='textcolor166'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor167'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> __init hello_5_init(</span><span id='textcolor168'><span class='ectt-0800'>void</span></span><span class='ectt-0800'>)</span>
|
|
<a id='x1-16122r45'></a><span class='ecrm-0500'>45</span><span class='ectt-0800'>{</span>
|
|
<a id='x1-16124r46'></a><span class='ecrm-0500'>46</span><span class='ectt-0800'> </span><span id='textcolor169'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> i;</span>
|
|
<a id='x1-16126r47'></a><span class='ecrm-0500'>47</span>
|
|
<a id='x1-16128r48'></a><span class='ecrm-0500'>48</span><span class='ectt-0800'> pr_info(</span><span id='textcolor170'><span class='ectt-0800'>"Hello, world 5</span></span><span id='textcolor171'><span class='ectt-0800'>\n</span></span><span id='textcolor172'><span class='ectt-0800'>=============</span></span><span id='textcolor173'><span class='ectt-0800'>\n</span></span><span id='textcolor174'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>);</span>
|
|
<a id='x1-16130r49'></a><span class='ecrm-0500'>49</span><span class='ectt-0800'> pr_info(</span><span id='textcolor175'><span class='ectt-0800'>"myshort is a short integer: %hd</span></span><span id='textcolor176'><span class='ectt-0800'>\n</span></span><span id='textcolor177'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>, myshort);</span>
|
|
<a id='x1-16132r50'></a><span class='ecrm-0500'>50</span><span class='ectt-0800'> pr_info(</span><span id='textcolor178'><span class='ectt-0800'>"myint is an integer: %d</span></span><span id='textcolor179'><span class='ectt-0800'>\n</span></span><span id='textcolor180'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>, myint);</span>
|
|
<a id='x1-16134r51'></a><span class='ecrm-0500'>51</span><span class='ectt-0800'> pr_info(</span><span id='textcolor181'><span class='ectt-0800'>"mylong is a long integer: %ld</span></span><span id='textcolor182'><span class='ectt-0800'>\n</span></span><span id='textcolor183'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>, mylong);</span>
|
|
<a id='x1-16136r52'></a><span class='ecrm-0500'>52</span><span class='ectt-0800'> pr_info(</span><span id='textcolor184'><span class='ectt-0800'>"mystring is a string: %s</span></span><span id='textcolor185'><span class='ectt-0800'>\n</span></span><span id='textcolor186'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>, mystring);</span>
|
|
<a id='x1-16138r53'></a><span class='ecrm-0500'>53</span>
|
|
<a id='x1-16140r54'></a><span class='ecrm-0500'>54</span><span class='ectt-0800'> </span><span id='textcolor187'><span class='ectt-0800'>for</span></span><span class='ectt-0800'> (i = 0; i < ARRAY_SIZE(myintarray); i++)</span>
|
|
<a id='x1-16142r55'></a><span class='ecrm-0500'>55</span><span class='ectt-0800'> pr_info(</span><span id='textcolor188'><span class='ectt-0800'>"myintarray[%d] = %d</span></span><span id='textcolor189'><span class='ectt-0800'>\n</span></span><span id='textcolor190'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>, i, myintarray[i]);</span>
|
|
<a id='x1-16144r56'></a><span class='ecrm-0500'>56</span>
|
|
<a id='x1-16146r57'></a><span class='ecrm-0500'>57</span><span class='ectt-0800'> pr_info(</span><span id='textcolor191'><span class='ectt-0800'>"got %d arguments for myintarray.</span></span><span id='textcolor192'><span class='ectt-0800'>\n</span></span><span id='textcolor193'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>, arr_argc);</span>
|
|
<a id='x1-16148r58'></a><span class='ecrm-0500'>58</span><span class='ectt-0800'> </span><span id='textcolor194'><span class='ectt-0800'>return</span></span><span class='ectt-0800'> 0;</span>
|
|
<a id='x1-16150r59'></a><span class='ecrm-0500'>59</span><span class='ectt-0800'>}</span>
|
|
<a id='x1-16152r60'></a><span class='ecrm-0500'>60</span>
|
|
<a id='x1-16154r61'></a><span class='ecrm-0500'>61</span><span id='textcolor195'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor196'><span class='ectt-0800'>void</span></span><span class='ectt-0800'> __exit hello_5_exit(</span><span id='textcolor197'><span class='ectt-0800'>void</span></span><span class='ectt-0800'>)</span>
|
|
<a id='x1-16156r62'></a><span class='ecrm-0500'>62</span><span class='ectt-0800'>{</span>
|
|
<a id='x1-16158r63'></a><span class='ecrm-0500'>63</span><span class='ectt-0800'> pr_info(</span><span id='textcolor198'><span class='ectt-0800'>"Goodbye, world 5</span></span><span id='textcolor199'><span class='ectt-0800'>\n</span></span><span id='textcolor200'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>);</span>
|
|
<a id='x1-16160r64'></a><span class='ecrm-0500'>64</span><span class='ectt-0800'>}</span>
|
|
<a id='x1-16162r65'></a><span class='ecrm-0500'>65</span>
|
|
<a id='x1-16164r66'></a><span class='ecrm-0500'>66</span><span class='ectt-0800'>module_init(hello_5_init);</span>
|
|
<a id='x1-16166r67'></a><span class='ecrm-0500'>67</span><span class='ectt-0800'>module_exit(hello_5_exit);</span></pre>
|
|
<!-- l. 412 --><p class='indent'> I would recommend playing around with this code:
|
|
</p>
|
|
<pre class='fancyvrb' id='fancyvrb26'><a id='x1-16194r1'></a><span class='ecrm-0500'>1</span><span class='colorbox' id='colorbox201'><span class='ectt-0800'>$</span></span><span class='ectt-0800'> sudo insmod hello-5.ko mystring=</span><span id='textcolor202'><span class='ectt-0800'>"bebop"</span></span><span class='ectt-0800'> myintArray=-1</span>
|
|
<a id='x1-16196r2'></a><span class='ecrm-0500'>2</span><span class='ectt-0800'>myshort is a </span><span id='textcolor203'><span class='ectt-0800'>short</span></span><span class='ectt-0800'> integer: 1</span>
|
|
<a id='x1-16198r3'></a><span class='ecrm-0500'>3</span><span class='ectt-0800'>myint is an integer: 420</span>
|
|
<a id='x1-16200r4'></a><span class='ecrm-0500'>4</span><span class='ectt-0800'>mylong is a </span><span id='textcolor204'><span class='ectt-0800'>long</span></span><span class='ectt-0800'> integer: 9999</span>
|
|
<a id='x1-16202r5'></a><span class='ecrm-0500'>5</span><span class='ectt-0800'>mystring is a string: bebop</span>
|
|
<a id='x1-16204r6'></a><span class='ecrm-0500'>6</span><span class='ectt-0800'>myintArray[0] = -1</span>
|
|
<a id='x1-16206r7'></a><span class='ecrm-0500'>7</span><span class='ectt-0800'>myintArray[1] = 420</span>
|
|
<a id='x1-16208r8'></a><span class='ecrm-0500'>8</span><span class='ectt-0800'>got 1 arguments </span><span id='textcolor205'><span class='ectt-0800'>for</span></span><span class='ectt-0800'> myintArray.</span>
|
|
<a id='x1-16210r9'></a><span class='ecrm-0500'>9</span>
|
|
<a id='x1-16212r10'></a><span class='ecrm-0500'>10</span><span class='colorbox' id='colorbox206'><span class='ectt-0800'>$</span></span><span class='ectt-0800'> sudo rmmod hello-5</span>
|
|
<a id='x1-16214r11'></a><span class='ecrm-0500'>11</span><span class='ectt-0800'>Goodbye, world 5</span>
|
|
<a id='x1-16216r12'></a><span class='ecrm-0500'>12</span>
|
|
<a id='x1-16218r13'></a><span class='ecrm-0500'>13</span><span class='colorbox' id='colorbox207'><span class='ectt-0800'>$</span></span><span class='ectt-0800'> sudo insmod hello-5.ko mystring=</span><span id='textcolor208'><span class='ectt-0800'>"supercalifragilisticexpialidocious"</span></span><span class='ectt-0800'> myintArray=-1,-1</span>
|
|
<a id='x1-16220r14'></a><span class='ecrm-0500'>14</span><span class='ectt-0800'>myshort is a </span><span id='textcolor209'><span class='ectt-0800'>short</span></span><span class='ectt-0800'> integer: 1</span>
|
|
<a id='x1-16222r15'></a><span class='ecrm-0500'>15</span><span class='ectt-0800'>myint is an integer: 420</span>
|
|
<a id='x1-16224r16'></a><span class='ecrm-0500'>16</span><span class='ectt-0800'>mylong is a </span><span id='textcolor210'><span class='ectt-0800'>long</span></span><span class='ectt-0800'> integer: 9999</span>
|
|
<a id='x1-16226r17'></a><span class='ecrm-0500'>17</span><span class='ectt-0800'>mystring is a string: supercalifragilisticexpialidocious</span>
|
|
<a id='x1-16228r18'></a><span class='ecrm-0500'>18</span><span class='ectt-0800'>myintArray[0] = -1</span>
|
|
<a id='x1-16230r19'></a><span class='ecrm-0500'>19</span><span class='ectt-0800'>myintArray[1] = -1</span>
|
|
<a id='x1-16232r20'></a><span class='ecrm-0500'>20</span><span class='ectt-0800'>got 2 arguments </span><span id='textcolor211'><span class='ectt-0800'>for</span></span><span class='ectt-0800'> myintArray.</span>
|
|
<a id='x1-16234r21'></a><span class='ecrm-0500'>21</span>
|
|
<a id='x1-16236r22'></a><span class='ecrm-0500'>22</span><span class='colorbox' id='colorbox212'><span class='ectt-0800'>$</span></span><span class='ectt-0800'> sudo rmmod hello-5</span>
|
|
<a id='x1-16238r23'></a><span class='ecrm-0500'>23</span><span class='ectt-0800'>Goodbye, world 5</span>
|
|
<a id='x1-16240r24'></a><span class='ecrm-0500'>24</span>
|
|
<a id='x1-16242r25'></a><span class='ecrm-0500'>25</span><span class='colorbox' id='colorbox213'><span class='ectt-0800'>$</span></span><span class='ectt-0800'> sudo insmod hello-5.ko mylong=hello</span>
|
|
<a id='x1-16244r26'></a><span class='ecrm-0500'>26</span><span class='ectt-0800'>hello-5.o: invalid argument syntax </span><span id='textcolor214'><span class='ectt-0800'>for</span></span><span class='ectt-0800'> mylong: </span><span id='textcolor215'><span class='tctt-0800'>'</span><span class='ectt-0800'>h</span><span class='tctt-0800'>'</span></span></pre>
|
|
<!-- l. 442 --><p class='noindent'>
|
|
</p>
|
|
<h4 class='subsectionHead' id='modules-spanning-multiple-files'><span class='titlemark'>4.6 </span> <a id='x1-170004.6'></a>Modules Spanning Multiple Files</h4>
|
|
<!-- l. 444 --><p class='noindent'>Sometimes it makes sense to divide a kernel module between several source
|
|
files.
|
|
</p><!-- l. 446 --><p class='indent'> Here is an example of such a kernel module.
|
|
</p>
|
|
<pre class='fancyvrb' id='fancyvrb27'><a id='x1-17002r1'></a><span class='ecrm-0500'>1</span><span id='textcolor216'><span class='ectt-0800'>/*</span></span>
|
|
<a id='x1-17004r2'></a><span class='ecrm-0500'>2</span><span id='textcolor217'><span class='ectt-0800'> * start.c - Illustration of multi filed modules</span></span>
|
|
<a id='x1-17006r3'></a><span class='ecrm-0500'>3</span><span id='textcolor218'><span class='ectt-0800'> */</span></span>
|
|
<a id='x1-17008r4'></a><span class='ecrm-0500'>4</span>
|
|
<a id='x1-17010r5'></a><span class='ecrm-0500'>5</span><span id='textcolor219'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor220'><span class='ectt-0800'><linux/kernel.h> /* We are doing kernel work */</span></span>
|
|
<a id='x1-17012r6'></a><span class='ecrm-0500'>6</span><span id='textcolor221'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor222'><span class='ectt-0800'><linux/module.h> /* Specifically, a module */</span></span>
|
|
<a id='x1-17014r7'></a><span class='ecrm-0500'>7</span>
|
|
<a id='x1-17016r8'></a><span class='ecrm-0500'>8</span><span id='textcolor223'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> init_module(</span><span id='textcolor224'><span class='ectt-0800'>void</span></span><span class='ectt-0800'>)</span>
|
|
<a id='x1-17018r9'></a><span class='ecrm-0500'>9</span><span class='ectt-0800'>{</span>
|
|
<a id='x1-17020r10'></a><span class='ecrm-0500'>10</span><span class='ectt-0800'> pr_info(</span><span id='textcolor225'><span class='ectt-0800'>"Hello, world - this is the kernel speaking</span></span><span id='textcolor226'><span class='ectt-0800'>\n</span></span><span id='textcolor227'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>);</span>
|
|
<a id='x1-17022r11'></a><span class='ecrm-0500'>11</span><span class='ectt-0800'> </span><span id='textcolor228'><span class='ectt-0800'>return</span></span><span class='ectt-0800'> 0;</span>
|
|
<a id='x1-17024r12'></a><span class='ecrm-0500'>12</span><span class='ectt-0800'>}</span>
|
|
<a id='x1-17026r13'></a><span class='ecrm-0500'>13</span>
|
|
<a id='x1-17028r14'></a><span class='ecrm-0500'>14</span><span class='ectt-0800'>MODULE_LICENSE(</span><span id='textcolor229'><span class='ectt-0800'>"GPL"</span></span><span class='ectt-0800'>);</span></pre>
|
|
<!-- l. 449 --><p class='indent'> The next file:
|
|
</p>
|
|
<pre class='fancyvrb' id='fancyvrb28'><a id='x1-17030r1'></a><span class='ecrm-0500'>1</span><span id='textcolor230'><span class='ectt-0800'>/*</span></span>
|
|
<a id='x1-17032r2'></a><span class='ecrm-0500'>2</span><span id='textcolor231'><span class='ectt-0800'> * stop.c - Illustration of multi filed modules</span></span>
|
|
<a id='x1-17034r3'></a><span class='ecrm-0500'>3</span><span id='textcolor232'><span class='ectt-0800'> */</span></span>
|
|
<a id='x1-17036r4'></a><span class='ecrm-0500'>4</span>
|
|
<a id='x1-17038r5'></a><span class='ecrm-0500'>5</span><span id='textcolor233'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor234'><span class='ectt-0800'><linux/kernel.h> /* We are doing kernel work */</span></span>
|
|
<a id='x1-17040r6'></a><span class='ecrm-0500'>6</span><span id='textcolor235'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor236'><span class='ectt-0800'><linux/module.h> /* Specifically, a module */</span></span>
|
|
<a id='x1-17042r7'></a><span class='ecrm-0500'>7</span>
|
|
<a id='x1-17044r8'></a><span class='ecrm-0500'>8</span><span id='textcolor237'><span class='ectt-0800'>void</span></span><span class='ectt-0800'> cleanup_module(</span><span id='textcolor238'><span class='ectt-0800'>void</span></span><span class='ectt-0800'>)</span>
|
|
<a id='x1-17046r9'></a><span class='ecrm-0500'>9</span><span class='ectt-0800'>{</span>
|
|
<a id='x1-17048r10'></a><span class='ecrm-0500'>10</span><span class='ectt-0800'> pr_info(</span><span id='textcolor239'><span class='ectt-0800'>"Short is the life of a kernel module</span></span><span id='textcolor240'><span class='ectt-0800'>\n</span></span><span id='textcolor241'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>);</span>
|
|
<a id='x1-17050r11'></a><span class='ecrm-0500'>11</span><span class='ectt-0800'>}</span>
|
|
<a id='x1-17052r12'></a><span class='ecrm-0500'>12</span>
|
|
<a id='x1-17054r13'></a><span class='ecrm-0500'>13</span><span class='ectt-0800'>MODULE_LICENSE(</span><span id='textcolor242'><span class='ectt-0800'>"GPL"</span></span><span class='ectt-0800'>);</span></pre>
|
|
<!-- l. 452 --><p class='indent'> And finally, the makefile:
|
|
</p><!-- l. 1 --><p class='indent'>
|
|
</p>
|
|
<pre class='fancyvrb' id='fancyvrb29'><a id='x1-17069r1'></a><span class='ecrm-0500'>1</span><span class='ectt-0800'>obj-m += hello-1.o</span>
|
|
<a id='x1-17071r2'></a><span class='ecrm-0500'>2</span><span class='ectt-0800'>obj-m += hello-2.o</span>
|
|
<a id='x1-17073r3'></a><span class='ecrm-0500'>3</span><span class='ectt-0800'>obj-m += hello-3.o</span>
|
|
<a id='x1-17075r4'></a><span class='ecrm-0500'>4</span><span class='ectt-0800'>obj-m += hello-4.o</span>
|
|
<a id='x1-17077r5'></a><span class='ecrm-0500'>5</span><span class='ectt-0800'>obj-m += hello-5.o</span>
|
|
<a id='x1-17079r6'></a><span class='ecrm-0500'>6</span><span class='ectt-0800'>obj-m += startstop.o</span>
|
|
<a id='x1-17081r7'></a><span class='ecrm-0500'>7</span><span class='ectt-0800'>startstop-objs := start.o stop.o</span>
|
|
<a id='x1-17083r8'></a><span class='ecrm-0500'>8</span>
|
|
<a id='x1-17085r9'></a><span class='ecrm-0500'>9</span><span class='ectt-0800'>all:</span>
|
|
<a id='x1-17087r10'></a><span class='ecrm-0500'>10</span><span class='ectt-0800'> make -C /lib/modules/</span><span class='colorbox' id='colorbox243'><span class='ectt-0800'>$</span></span><span class='ectt-0800'>(shell uname -r)/build M=</span><span class='colorbox' id='colorbox244'><span class='ectt-0800'>$</span></span><span class='ectt-0800'>(PWD) modules</span>
|
|
<a id='x1-17089r11'></a><span class='ecrm-0500'>11</span>
|
|
<a id='x1-17091r12'></a><span class='ecrm-0500'>12</span><span class='ectt-0800'>clean:</span>
|
|
<a id='x1-17093r13'></a><span class='ecrm-0500'>13</span><span class='ectt-0800'> make -C /lib/modules/</span><span class='colorbox' id='colorbox245'><span class='ectt-0800'>$</span></span><span class='ectt-0800'>(shell uname -r)/build M=</span><span class='colorbox' id='colorbox246'><span class='ectt-0800'>$</span></span><span class='ectt-0800'>(PWD) clean</span></pre>
|
|
|
|
|
|
|
|
<!-- l. 470 --><p class='indent'> This is the complete makefile for all the examples we have seen so far. The first
|
|
five lines are nothing special, but for the last example we will need two lines.
|
|
First we invent an object name for our combined module, second we tell
|
|
<code> <span class='ectt-1000'>make</span>
|
|
</code> what object files are part of that module.
|
|
</p><!-- l. 474 --><p class='noindent'>
|
|
</p>
|
|
<h4 class='subsectionHead' id='building-modules-for-a-precompiled-kernel'><span class='titlemark'>4.7 </span> <a id='x1-180004.7'></a>Building modules for a precompiled kernel</h4>
|
|
<!-- l. 476 --><p class='noindent'>Obviously, we strongly suggest you to recompile your kernel, so that you can enable
|
|
a number of useful debugging features, such as forced module unloading
|
|
(<code> <span class='ectt-1000'>MODULE_FORCE_UNLOAD</span>
|
|
</code>): when this option is enabled, you can force the kernel to unload a module even when it believes
|
|
it is unsafe, via a <code> <span class='ectt-1000'>sudo rmmod -f module</span>
|
|
</code> command. This option can save you a lot of time and a number of reboots during
|
|
the development of a module. If you do not want to recompile your kernel then you
|
|
should consider running the examples within a test distribution on a virtual machine.
|
|
If you mess anything up then you can easily reboot or restore the virtual machine
|
|
(VM).
|
|
</p><!-- l. 481 --><p class='indent'> There are a number of cases in which you may want to load your module into a
|
|
precompiled running kernel, such as the ones shipped with common Linux
|
|
distributions, or a kernel you have compiled in the past. In certain circumstances you
|
|
could require to compile and insert a module into a running kernel which you are not
|
|
allowed to recompile, or on a machine that you prefer not to reboot. If you
|
|
can’t think of a case that will force you to use modules for a precompiled
|
|
kernel you might want to skip this and treat the rest of this chapter as a big
|
|
footnote.
|
|
</p><!-- l. 485 --><p class='indent'> Now, if you just install a kernel source tree, use it to compile your kernel module
|
|
and you try to insert your module into the kernel, in most cases you would obtain an
|
|
error as follows:
|
|
|
|
|
|
|
|
</p>
|
|
<pre class='verbatim' id='verbatim-2'>
|
|
insmod: ERROR: could not insert module poet.ko: Invalid module format
|
|
</pre>
|
|
<!-- l. 489 --><p class='nopar'>
|
|
</p><!-- l. 491 --><p class='indent'> Less cryptic information is logged to the systemd journal:
|
|
|
|
|
|
|
|
</p>
|
|
<pre class='verbatim' id='verbatim-3'>
|
|
kernel: poet: disagrees about version of symbol module_layout
|
|
</pre>
|
|
<!-- l. 495 --><p class='nopar'>
|
|
</p><!-- l. 497 --><p class='indent'> In other words, your kernel refuses to accept your module because version strings
|
|
(more precisely, <span class='ecti-1000'>version magic</span>, see <a href='https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/tree/include/linux/vermagic.h'>include/linux/vermagic.h</a>) do not match. Incidentally,
|
|
version magic strings are stored in the module object in the form of a static string, starting
|
|
with <code> <span class='ectt-1000'>vermagic:</span>
|
|
</code>. Version data are inserted in your module when it is linked against the <span class='obeylines-h'><span class='verb'><span class='ectt-1000'>kernel/module.o</span></span></span>
|
|
file. To inspect version magics and other strings stored in a given module, issue the
|
|
command <code> <span class='ectt-1000'>modinfo module.ko</span>
|
|
</code>:
|
|
|
|
|
|
|
|
</p>
|
|
<pre class='verbatim' id='verbatim-4'>
|
|
$ modinfo hello-4.ko
|
|
description: A sample driver
|
|
author: LKMPG
|
|
license: GPL
|
|
srcversion: B2AA7FBFCC2C39AED665382
|
|
depends:
|
|
retpoline: Y
|
|
name: hello_4
|
|
vermagic: 5.4.0-70-generic SMP mod_unload modversions
|
|
</pre>
|
|
<!-- l. 512 --><p class='nopar'>
|
|
</p><!-- l. 514 --><p class='indent'> To overcome this problem we could resort to the <span class='obeylines-h'><span class='verb'><span class='ectt-1000'>--force-vermagic</span></span></span> option,
|
|
but this solution is potentially unsafe, and unquestionably unacceptable
|
|
in production modules. Consequently, we want to compile our module in
|
|
an environment which was identical to the one in which our precompiled
|
|
kernel was built. How to do this, is the subject of the remainder of this
|
|
chapter.
|
|
</p><!-- l. 518 --><p class='indent'> First of all, make sure that a kernel source tree is available, having exactly the same
|
|
version as your current kernel. Then, find the configuration file which was used to
|
|
compile your precompiled kernel. Usually, this is available in your current <span class='obeylines-h'><span class='verb'><span class='ectt-1000'>boot</span></span></span> directory,
|
|
under a name like <span class='obeylines-h'><span class='verb'><span class='ectt-1000'>config-5.14.x</span></span></span>. You may just want to copy it to your kernel source
|
|
tree: <code> <span class='ectt-1000'>cp /boot/config-</span><span id='textcolor247'><span class='tctt-1000'>`</span></span><span class='ectt-1000'>uname -r</span><span id='textcolor248'><span class='tctt-1000'>`</span></span><span class='ectt-1000'> .config</span>
|
|
</code>.
|
|
</p><!-- l. 523 --><p class='indent'> Let’s focus again on the previous error message: a closer look at the version magic
|
|
strings suggests that, even with two configuration files which are exactly the same, a
|
|
slight difference in the version magic could be possible, and it is sufficient to prevent
|
|
insertion of the module into the kernel. That slight difference, namely the
|
|
custom string which appears in the module’s version magic and not in the
|
|
kernel’s one, is due to a modification with respect to the original, in the
|
|
makefile that some distributions include. Then, examine your <span class='obeylines-h'><span class='verb'><span class='ectt-1000'>Makefile</span></span></span>,
|
|
and make sure that the specified version information matches exactly the
|
|
one used for your current kernel. For example, you makefile could start as
|
|
follows:
|
|
|
|
|
|
|
|
</p>
|
|
<pre class='verbatim' id='verbatim-5'>
|
|
VERSION = 5
|
|
PATCHLEVEL = 14
|
|
SUBLEVEL = 0
|
|
EXTRAVERSION = -rc2
|
|
</pre>
|
|
<!-- l. 533 --><p class='nopar'>
|
|
</p><!-- l. 535 --><p class='indent'> In this case, you need to restore the value of symbol <span class='ecbx-1000'>EXTRAVERSION </span>to
|
|
<span class='ecbx-1000'>-rc2</span>. We suggest to keep a backup copy of the makefile used to compile your kernel
|
|
available in <span class='obeylines-h'><span class='verb'><span class='ectt-1000'>/lib/modules/5.14.0-rc2/build</span></span></span>. A simple command as following
|
|
should suffice.
|
|
</p>
|
|
<pre class='fancyvrb' id='fancyvrb30'><a id='x1-18008r1'></a><span class='ecrm-0500'>1</span><span class='ectt-1000'>cp /lib/modules/</span><span id='textcolor249'><span class='tctt-1000'>`</span></span><span class='ectt-1000'>uname -r</span><span id='textcolor250'><span class='tctt-1000'>`</span></span><span class='ectt-1000'>/build/Makefile linux-</span><span id='textcolor251'><span class='tctt-1000'>`</span></span><span class='ectt-1000'>uname -r</span><span id='textcolor252'><span class='tctt-1000'>`</span></span></pre>
|
|
<!-- l. 541 --><p class='noindent'>Here <code> <span class='ectt-1000'>linux-</span><span id='textcolor253'><span class='tctt-1000'>`</span></span><span class='ectt-1000'>uname -r</span><span id='textcolor254'><span class='tctt-1000'>`</span></span>
|
|
</code> is the Linux kernel source you are attempting to build.
|
|
</p><!-- l. 543 --><p class='indent'> Now, please run <code> <span class='ectt-1000'>make</span>
|
|
</code> to update configuration and version headers and objects:
|
|
|
|
|
|
|
|
</p>
|
|
<pre class='verbatim' id='verbatim-6'>
|
|
$ make
|
|
SYNC include/config/auto.conf.cmd
|
|
HOSTCC scripts/basic/fixdep
|
|
HOSTCC scripts/kconfig/conf.o
|
|
HOSTCC scripts/kconfig/confdata.o
|
|
HOSTCC scripts/kconfig/expr.o
|
|
LEX scripts/kconfig/lexer.lex.c
|
|
YACC scripts/kconfig/parser.tab.[ch]
|
|
HOSTCC scripts/kconfig/preprocess.o
|
|
HOSTCC scripts/kconfig/symbol.o
|
|
HOSTCC scripts/kconfig/util.o
|
|
HOSTCC scripts/kconfig/lexer.lex.o
|
|
HOSTCC scripts/kconfig/parser.tab.o
|
|
HOSTLD scripts/kconfig/conf
|
|
</pre>
|
|
<!-- l. 560 --><p class='nopar'>
|
|
</p><!-- l. 562 --><p class='indent'> If you do not desire to actually compile the kernel, you can interrupt the build
|
|
process (CTRL-C) just after the SPLIT line, because at that time, the files you need
|
|
will be are ready. Now you can turn back to the directory of your module and
|
|
compile it: It will be built exactly according to your current kernel settings, and it
|
|
will load into it without any errors.
|
|
</p><!-- l. 565 --><p class='noindent'>
|
|
</p>
|
|
<h3 class='sectionHead' id='preliminaries'><span class='titlemark'>5 </span> <a id='x1-190005'></a>Preliminaries</h3>
|
|
<!-- l. 566 --><p class='noindent'>
|
|
</p>
|
|
<h4 class='subsectionHead' id='how-modules-begin-and-end'><span class='titlemark'>5.1 </span> <a id='x1-200005.1'></a>How modules begin and end</h4>
|
|
<!-- l. 568 --><p class='noindent'>A program usually begins with a <code> <span class='ectt-1000'>main()</span>
|
|
</code> function, executes a bunch of instructions and terminates upon completion of those
|
|
instructions. Kernel modules work a bit differently. A module always begin with either
|
|
the <code> <span class='ectt-1000'>init_module</span>
|
|
</code> or the function you specify with <code> <span class='ectt-1000'>module_init</span>
|
|
</code> call. This is the entry function for modules; it tells the kernel what functionality the
|
|
module provides and sets up the kernel to run the module’s functions when they
|
|
are needed. Once it does this, entry function returns and the module does
|
|
nothing until the kernel wants to do something with the code that the module
|
|
provides.
|
|
|
|
|
|
|
|
</p><!-- l. 573 --><p class='indent'> All modules end by calling either <code> <span class='ectt-1000'>cleanup_module</span>
|
|
</code> or the function you specify with the <code> <span class='ectt-1000'>module_exit</span>
|
|
</code> call. This is the exit function for modules; it undoes whatever entry function did. It
|
|
unregisters the functionality that the entry function registered.
|
|
</p><!-- l. 577 --><p class='indent'> Every module must have an entry function and an exit function. Since there’s
|
|
more than one way to specify entry and exit functions, I will try my best to use the
|
|
terms “entry function” and “exit function”, but if I slip and simply refer to them as
|
|
<code> <span class='ectt-1000'>init_module</span>
|
|
</code> and <code> <span class='ectt-1000'>cleanup_module</span>
|
|
</code>, I think you will know what I mean.
|
|
</p><!-- l. 580 --><p class='noindent'>
|
|
</p>
|
|
<h4 class='subsectionHead' id='functions-available-to-modules'><span class='titlemark'>5.2 </span> <a id='x1-210005.2'></a>Functions available to modules</h4>
|
|
<!-- l. 582 --><p class='noindent'>Programmers use functions they do not define all the time. A prime example of this
|
|
is <code> <span class='ectt-1000'>printf()</span>
|
|
</code>. You use these library functions which are provided by the standard C
|
|
library, libc. The definitions for these functions do not actually enter
|
|
your program until the linking stage, which insures that the code (for
|
|
<code> <span class='ectt-1000'>printf()</span>
|
|
</code> for example) is available, and fixes the call instruction to point to that
|
|
code.
|
|
</p><!-- l. 587 --><p class='indent'> Kernel modules are different here, too. In the hello world
|
|
example, you might have noticed that we used a function,
|
|
<code> <span class='ectt-1000'>pr_info()</span>
|
|
</code> but did not include a standard I/O library. That is because modules are object files whose symbols
|
|
get resolved upon <code> <span class='ectt-1000'>insmod</span>
|
|
</code>’ing. The definition for the symbols comes from the kernel itself; the only
|
|
external functions you can use are the ones provided by the kernel. If you’re
|
|
curious about what symbols have been exported by your kernel, take a look at
|
|
<span class='obeylines-h'><span class='verb'><span class='ectt-1000'>/proc/kallsyms</span></span></span>.
|
|
</p><!-- l. 592 --><p class='indent'> One point to keep in mind is the difference between library functions and system
|
|
calls. Library functions are higher level, run completely in user space and
|
|
provide a more convenient interface for the programmer to the functions
|
|
that do the real work — system calls. System calls run in kernel mode on
|
|
the user’s behalf and are provided by the kernel itself. The library function
|
|
<code> <span class='ectt-1000'>printf()</span>
|
|
</code> may look like a very general printing function, but all it really does is format the
|
|
data into strings and write the string data using the low-level system call
|
|
<code> <span class='ectt-1000'>write()</span>
|
|
</code>, which then sends the data to standard output.
|
|
</p><!-- l. 596 --><p class='indent'> Would you like to see what system calls are made by
|
|
<code> <span class='ectt-1000'>printf()</span>
|
|
|
|
|
|
|
|
</code>? It is easy! Compile the following program:
|
|
</p><!-- l. 1 --><p class='indent'>
|
|
</p>
|
|
<pre class='fancyvrb' id='fancyvrb31'><a id='x1-21016r1'></a><span class='ecrm-0500'>1</span><span id='textcolor255'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor256'><span class='ectt-0800'><stdio.h></span></span>
|
|
<a id='x1-21018r2'></a><span class='ecrm-0500'>2</span>
|
|
<a id='x1-21020r3'></a><span class='ecrm-0500'>3</span><span id='textcolor257'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> main(</span><span id='textcolor258'><span class='ectt-0800'>void</span></span><span class='ectt-0800'>)</span>
|
|
<a id='x1-21022r4'></a><span class='ecrm-0500'>4</span><span class='ectt-0800'>{</span>
|
|
<a id='x1-21024r5'></a><span class='ecrm-0500'>5</span><span class='ectt-0800'> printf(</span><span id='textcolor259'><span class='ectt-0800'>"hello"</span></span><span class='ectt-0800'>);</span>
|
|
<a id='x1-21026r6'></a><span class='ecrm-0500'>6</span><span class='ectt-0800'> </span><span id='textcolor260'><span class='ectt-0800'>return</span></span><span class='ectt-0800'> 0;</span>
|
|
<a id='x1-21028r7'></a><span class='ecrm-0500'>7</span><span class='ectt-0800'>}</span></pre>
|
|
<!-- l. 610 --><p class='indent'> with <code> <span class='ectt-1000'>gcc -Wall -o hello hello.c</span>
|
|
</code>. Run the executable with <code> <span class='ectt-1000'>strace ./hello</span>
|
|
</code>. Are you impressed? Every line you see corresponds to a system call. <a href='https://strace.io/'>strace</a> is a
|
|
handy program that gives you details about what system calls a program is
|
|
making, including which call is made, what its arguments are and what it
|
|
returns. It is an invaluable tool for figuring out things like what files a program
|
|
is trying to access. Towards the end, you will see a line which looks like
|
|
<code> <span class='ectt-1000'>write(1, </span><span id='textcolor261'><span class='ectt-1000'>"hello"</span></span><span class='ectt-1000'>, 5hello)</span>
|
|
</code>. There it is. The face behind the <code> <span class='ectt-1000'>printf()</span>
|
|
</code> mask. You may not be familiar with write, since most people use library functions for file
|
|
I/O (like <code> <span class='ectt-1000'>fopen</span>
|
|
</code>, <code> <span class='ectt-1000'>fputs</span>
|
|
</code>, <code> <span class='ectt-1000'>fclose</span>
|
|
</code>). If that is the case, try looking at man 2 write. The 2nd man section is devoted to system
|
|
calls (like <code> <span class='ectt-1000'>kill()</span>
|
|
</code> and <code> <span class='ectt-1000'>read()</span>
|
|
</code>). The 3rd man section is devoted to library calls, which you would probably be more familiar
|
|
with (like <code> <span class='ectt-1000'>cosh()</span>
|
|
</code> and <code> <span class='ectt-1000'>random()</span>
|
|
</code>).
|
|
</p><!-- l. 624 --><p class='indent'> You can even write modules to replace the kernel’s system calls, which we will do
|
|
shortly. Crackers often make use of this sort of thing for backdoors or trojans, but
|
|
you can write your own modules to do more benign things, like have the kernel
|
|
write Tee hee, that tickles! every time someone tries to delete a file on your
|
|
system.
|
|
</p><!-- l. 627 --><p class='noindent'>
|
|
</p>
|
|
<h4 class='subsectionHead' id='user-space-vs-kernel-space'><span class='titlemark'>5.3 </span> <a id='x1-220005.3'></a>User Space vs Kernel Space</h4>
|
|
<!-- l. 629 --><p class='noindent'>A kernel is all about access to resources, whether the resource in question happens to
|
|
be a video card, a hard drive or even memory. Programs often compete for the same
|
|
resource. As I just saved this document, updatedb started updating the locate
|
|
database. My vim session and updatedb are both using the hard drive concurrently.
|
|
The kernel needs to keep things orderly, and not give users access to resources
|
|
whenever they feel like it. To this end, a CPU can run in different modes. Each mode
|
|
gives a different level of freedom to do what you want on the system. The Intel 80386
|
|
architecture had 4 of these modes, which were called rings. Unix uses only
|
|
two rings; the highest ring (ring 0, also known as “supervisor mode” where
|
|
everything is allowed to happen) and the lowest ring, which is called “user
|
|
mode”.
|
|
|
|
|
|
|
|
</p><!-- l. 637 --><p class='indent'> Recall the discussion about library functions vs system calls. Typically, you use a
|
|
library function in user mode. The library function calls one or more system calls,
|
|
and these system calls execute on the library function’s behalf, but do so in
|
|
supervisor mode since they are part of the kernel itself. Once the system call
|
|
completes its task, it returns and execution gets transfered back to user
|
|
mode.
|
|
</p><!-- l. 642 --><p class='noindent'>
|
|
</p>
|
|
<h4 class='subsectionHead' id='name-space'><span class='titlemark'>5.4 </span> <a id='x1-230005.4'></a>Name Space</h4>
|
|
<!-- l. 644 --><p class='noindent'>When you write a small C program, you use variables which are convenient and make
|
|
sense to the reader. If, on the other hand, you are writing routines which will be part
|
|
of a bigger problem, any global variables you have are part of a community of other
|
|
peoples’ global variables; some of the variable names can clash. When a program has
|
|
lots of global variables which aren’t meaningful enough to be distinguished, you get
|
|
namespace pollution. In large projects, effort must be made to remember reserved
|
|
names, and to find ways to develop a scheme for naming unique variable names and
|
|
symbols.
|
|
</p><!-- l. 649 --><p class='indent'> When writing kernel code, even the smallest module will be linked against the
|
|
entire kernel, so this is definitely an issue. The best way to deal with this is to declare
|
|
all your variables as static and to use a well-defined prefix for your symbols. By
|
|
convention, all kernel prefixes are lowercase. If you do not want to declare everything
|
|
as static, another option is to declare a symbol table and register it with the kernel.
|
|
We will get to this later.
|
|
</p><!-- l. 654 --><p class='indent'> The file <span class='obeylines-h'><span class='verb'><span class='ectt-1000'>/proc/kallsyms</span></span></span> holds all the symbols that the kernel knows about and
|
|
which are therefore accessible to your modules since they share the kernel’s
|
|
codespace.
|
|
</p><!-- l. 656 --><p class='noindent'>
|
|
</p>
|
|
<h4 class='subsectionHead' id='code-space'><span class='titlemark'>5.5 </span> <a id='x1-240005.5'></a>Code space</h4>
|
|
<!-- l. 658 --><p class='noindent'>Memory management is a very complicated subject and the majority of O’Reilly’s
|
|
<a href='https://www.oreilly.com/library/view/understanding-the-linux/0596005652/'>Understanding The Linux Kernel</a> exclusively covers memory management!
|
|
We are not setting out to be experts on memory managements, but we do
|
|
need to know a couple of facts to even begin worrying about writing real
|
|
modules.
|
|
</p><!-- l. 661 --><p class='indent'> If you have not thought about what a segfault really means, you may be surprised
|
|
to hear that pointers do not actually point to memory locations. Not real
|
|
ones, anyway. When a process is created, the kernel sets aside a portion of
|
|
real physical memory and hands it to the process to use for its executing
|
|
code, variables, stack, heap and other things which a computer scientist
|
|
would know about. This memory begins with 0x00000000 and extends up to
|
|
whatever it needs to be. Since the memory space for any two processes do not
|
|
|
|
|
|
|
|
overlap, every process that can access a memory address, say 0xbffff978, would
|
|
be accessing a different location in real physical memory! The processes
|
|
would be accessing an index named 0xbffff978 which points to some kind of
|
|
offset into the region of memory set aside for that particular process. For
|
|
the most part, a process like our Hello, World program can’t access the
|
|
space of another process, although there are ways which we will talk about
|
|
later.
|
|
</p><!-- l. 668 --><p class='indent'> The kernel has its own space of memory as well. Since a module is code which
|
|
can be dynamically inserted and removed in the kernel (as opposed to a
|
|
semi-autonomous object), it shares the kernel’s codespace rather than having its own.
|
|
Therefore, if your module segfaults, the kernel segfaults. And if you start writing
|
|
over data because of an off-by-one error, then you’re trampling on kernel
|
|
data (or code). This is even worse than it sounds, so try your best to be
|
|
careful.
|
|
</p><!-- l. 673 --><p class='indent'> By the way, I would like to point out that the above discussion is true for any
|
|
operating system which uses a monolithic kernel. This is not quite the same thing as
|
|
<span class='ecti-1000'>"building all your modules into the kernel"</span>, although the idea is the same. There are
|
|
things called microkernels which have modules which get their own codespace. The
|
|
<a href='https://www.gnu.org/software/hurd/'>GNU Hurd</a> and the <a href='https://fuchsia.dev/fuchsia-src/concepts/kernel'>Zircon kernel</a> of Google Fuchsia are two examples of a
|
|
microkernel.
|
|
</p><!-- l. 678 --><p class='noindent'>
|
|
</p>
|
|
<h4 class='subsectionHead' id='device-drivers'><span class='titlemark'>5.6 </span> <a id='x1-250005.6'></a>Device Drivers</h4>
|
|
<!-- l. 680 --><p class='noindent'>One class of module is the device driver, which provides functionality for hardware
|
|
like a serial port. On Unix, each piece of hardware is represented by a file located in
|
|
<span class='obeylines-h'><span class='verb'><span class='ectt-1000'>/dev</span></span></span> named a device file which provides the means to communicate with the
|
|
hardware. The device driver provides the communication on behalf of a
|
|
user program. So the es1370.ko sound card device driver might connect the
|
|
<span class='obeylines-h'><span class='verb'><span class='ectt-1000'>/dev/sound</span></span></span> device file to the Ensoniq IS1370 sound card. A userspace program like
|
|
mp3blaster can use <span class='obeylines-h'><span class='verb'><span class='ectt-1000'>/dev/sound</span></span></span> without ever knowing what kind of sound card is
|
|
installed.
|
|
</p><!-- l. 687 --><p class='indent'> Let’s look at some device files. Here are device files which represent the first three
|
|
partitions on the primary master IDE hard drive:
|
|
|
|
|
|
|
|
</p>
|
|
<pre class='verbatim' id='verbatim-7'>
|
|
$ ls -l /dev/hda[1-3]
|
|
brw-rw---- 1 root disk 3, 1 Jul 5 2000 /dev/hda1
|
|
brw-rw---- 1 root disk 3, 2 Jul 5 2000 /dev/hda2
|
|
brw-rw---- 1 root disk 3, 3 Jul 5 2000 /dev/hda3
|
|
</pre>
|
|
<!-- l. 696 --><p class='nopar'>
|
|
</p><!-- l. 698 --><p class='indent'> Notice the column of numbers separated by a comma. The first number is called
|
|
the device’s major number. The second number is the minor number. The major
|
|
number tells you which driver is used to access the hardware. Each driver is assigned
|
|
a unique major number; all device files with the same major number are controlled
|
|
by the same driver. All the above major numbers are 3, because they’re all controlled
|
|
by the same driver.
|
|
</p><!-- l. 705 --><p class='indent'> The minor number is used by the driver to distinguish between the various
|
|
hardware it controls. Returning to the example above, although all three devices are
|
|
handled by the same driver they have unique minor numbers because the driver sees
|
|
them as being different pieces of hardware.
|
|
</p><!-- l. 708 --><p class='indent'> Devices are divided into two types: character devices and block devices. The
|
|
difference is that block devices have a buffer for requests, so they can choose the best
|
|
order in which to respond to the requests. This is important in the case of storage
|
|
devices, where it is faster to read or write sectors which are close to each
|
|
other, rather than those which are further apart. Another difference is that
|
|
block devices can only accept input and return output in blocks (whose size
|
|
can vary according to the device), whereas character devices are allowed
|
|
to use as many or as few bytes as they like. Most devices in the world are
|
|
character, because they don’t need this type of buffering, and they don’t
|
|
operate with a fixed block size. You can tell whether a device file is for a block
|
|
device or a character device by looking at the first character in the output of
|
|
<code> <span class='ectt-1000'>ls -l</span>
|
|
</code>. If it is ‘b’ then it is a block device, and if it is ‘c’ then it is a character device. The
|
|
devices you see above are block devices. Here are some character devices (the serial
|
|
ports):
|
|
|
|
|
|
|
|
</p>
|
|
<pre class='verbatim' id='verbatim-8'>
|
|
crw-rw---- 1 root dial 4, 64 Feb 18 23:34 /dev/ttyS0
|
|
crw-r----- 1 root dial 4, 65 Nov 17 10:26 /dev/ttyS1
|
|
crw-rw---- 1 root dial 4, 66 Jul 5 2000 /dev/ttyS2
|
|
crw-rw---- 1 root dial 4, 67 Jul 5 2000 /dev/ttyS3
|
|
</pre>
|
|
<!-- l. 722 --><p class='nopar'>
|
|
</p><!-- l. 724 --><p class='indent'> If you want to see which major numbers have been assigned, you can look at
|
|
<a href='https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/tree/Documentation/admin-guide/devices.txt'>Documentation/admin-guide/devices.txt</a>.
|
|
</p><!-- l. 726 --><p class='indent'> When the system was installed, all of those device files were created by the
|
|
<code> <span class='ectt-1000'>mknod</span>
|
|
</code> command. To create a new char device named <span class='obeylines-h'><span class='verb'><span class='ectt-1000'>coffee</span></span></span> with major/minor number 12 and 2,
|
|
simply do <code> <span class='ectt-1000'>mknod /dev/coffee c 12 2</span>
|
|
</code>. You do not have to put your device files into <span class='obeylines-h'><span class='verb'><span class='ectt-1000'>/dev</span></span></span>, but it is done by convention.
|
|
Linus put his device files in <span class='obeylines-h'><span class='verb'><span class='ectt-1000'>/dev</span></span></span>, and so should you. However, when creating a
|
|
device file for testing purposes, it is probably OK to place it in your working
|
|
directory where you compile the kernel module. Just be sure to put it in the right
|
|
place when you’re done writing the device driver.
|
|
</p><!-- l. 733 --><p class='indent'> I would like to make a few last points which are implicit from the above
|
|
discussion, but I would like to make them explicit just in case. When a device file is
|
|
accessed, the kernel uses the major number of the file to determine which driver
|
|
should be used to handle the access. This means that the kernel doesn’t really need
|
|
to use or even know about the minor number. The driver itself is the only thing that
|
|
cares about the minor number. It uses the minor number to distinguish between
|
|
different pieces of hardware.
|
|
</p><!-- l. 739 --><p class='indent'> By the way, when I say <span class='ecti-1000'>"hardware"</span>, I mean something a bit more abstract
|
|
than a PCI card that you can hold in your hand. Look at these two device
|
|
files:
|
|
|
|
|
|
|
|
</p>
|
|
<pre class='verbatim' id='verbatim-9'>
|
|
$ ls -l /dev/sda /dev/sdb
|
|
brw-rw---- 1 root disk 8, 0 Jan 3 09:02 /dev/sda
|
|
brw-rw---- 1 root disk 8, 16 Jan 3 09:02 /dev/sdb
|
|
</pre>
|
|
<!-- l. 746 --><p class='nopar'>
|
|
</p><!-- l. 748 --><p class='indent'> By now you can look at these two device files and know instantly that they are
|
|
block devices and are handled by same driver (block major 8). Sometimes two device
|
|
files with the same major but different minor number can actually represent the same
|
|
piece of physical hardware. So just be aware that the word “hardware” in our
|
|
discussion can mean something very abstract.
|
|
</p><!-- l. 752 --><p class='noindent'>
|
|
</p>
|
|
<h3 class='sectionHead' id='character-device-drivers'><span class='titlemark'>6 </span> <a id='x1-260006'></a>Character Device drivers</h3>
|
|
<!-- l. 754 --><p class='noindent'>
|
|
</p>
|
|
<h4 class='subsectionHead' id='the-fileoperations-structure'><span class='titlemark'>6.1 </span> <a id='x1-270006.1'></a>The file_operations Structure</h4>
|
|
<!-- l. 756 --><p class='noindent'>The <code> <span class='ectt-1000'>file_operations</span>
|
|
</code> structure is defined in <a href='https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/tree/include/linux/fs.h'>include/linux/fs.h</a>, and holds pointers to functions defined by
|
|
the driver that perform various operations on the device. Each field of the structure
|
|
corresponds to the address of some function defined by the driver to handle a
|
|
requested operation.
|
|
</p><!-- l. 759 --><p class='indent'> For example, every character driver needs to define a function that reads from the
|
|
device. The <code> <span class='ectt-1000'>file_operations</span>
|
|
</code> structure holds the address of the module’s function that performs that operation.
|
|
Here is what the definition looks like for kernel 5.4:
|
|
</p><!-- l. 1 --><p class='indent'>
|
|
</p>
|
|
<pre class='fancyvrb' id='fancyvrb32'><a id='x1-27042r1'></a><span class='ecrm-0500'>1</span><span id='textcolor262'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> file_operations {</span>
|
|
<a id='x1-27044r2'></a><span class='ecrm-0500'>2</span><span class='ectt-0800'> </span><span id='textcolor263'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> module *owner;</span>
|
|
<a id='x1-27046r3'></a><span class='ecrm-0500'>3</span><span class='ectt-0800'> loff_t (*llseek) (</span><span id='textcolor264'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> file *, loff_t, </span><span id='textcolor265'><span class='ectt-0800'>int</span></span><span class='ectt-0800'>);</span>
|
|
<a id='x1-27048r4'></a><span class='ecrm-0500'>4</span><span class='ectt-0800'> </span><span id='textcolor266'><span class='ectt-0800'>ssize_t</span></span><span class='ectt-0800'> (*read) (</span><span id='textcolor267'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> file *, </span><span id='textcolor268'><span class='ectt-0800'>char</span></span><span class='ectt-0800'> __user *, </span><span id='textcolor269'><span class='ectt-0800'>size_t</span></span><span class='ectt-0800'>, loff_t *);</span>
|
|
<a id='x1-27050r5'></a><span class='ecrm-0500'>5</span><span class='ectt-0800'> </span><span id='textcolor270'><span class='ectt-0800'>ssize_t</span></span><span class='ectt-0800'> (*write) (</span><span id='textcolor271'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> file *, </span><span id='textcolor272'><span class='ectt-0800'>const</span></span><span class='ectt-0800'> </span><span id='textcolor273'><span class='ectt-0800'>char</span></span><span class='ectt-0800'> __user *, </span><span id='textcolor274'><span class='ectt-0800'>size_t</span></span><span class='ectt-0800'>, loff_t *);</span>
|
|
<a id='x1-27052r6'></a><span class='ecrm-0500'>6</span><span class='ectt-0800'> </span><span id='textcolor275'><span class='ectt-0800'>ssize_t</span></span><span class='ectt-0800'> (*read_iter) (</span><span id='textcolor276'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> kiocb *, </span><span id='textcolor277'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> iov_iter *);</span>
|
|
<a id='x1-27054r7'></a><span class='ecrm-0500'>7</span><span class='ectt-0800'> </span><span id='textcolor278'><span class='ectt-0800'>ssize_t</span></span><span class='ectt-0800'> (*write_iter) (</span><span id='textcolor279'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> kiocb *, </span><span id='textcolor280'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> iov_iter *);</span>
|
|
<a id='x1-27056r8'></a><span class='ecrm-0500'>8</span><span class='ectt-0800'> </span><span id='textcolor281'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> (*iopoll)(</span><span id='textcolor282'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> kiocb *kiocb, </span><span id='textcolor283'><span class='ectt-0800'>bool</span></span><span class='ectt-0800'> spin);</span>
|
|
<a id='x1-27058r9'></a><span class='ecrm-0500'>9</span><span class='ectt-0800'> </span><span id='textcolor284'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> (*iterate) (</span><span id='textcolor285'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> file *, </span><span id='textcolor286'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> dir_context *);</span>
|
|
<a id='x1-27060r10'></a><span class='ecrm-0500'>10</span><span class='ectt-0800'> </span><span id='textcolor287'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> (*iterate_shared) (</span><span id='textcolor288'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> file *, </span><span id='textcolor289'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> dir_context *);</span>
|
|
<a id='x1-27062r11'></a><span class='ecrm-0500'>11</span><span class='ectt-0800'> __poll_t (*poll) (</span><span id='textcolor290'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> file *, </span><span id='textcolor291'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> poll_table_struct *);</span>
|
|
<a id='x1-27064r12'></a><span class='ecrm-0500'>12</span><span class='ectt-0800'> </span><span id='textcolor292'><span class='ectt-0800'>long</span></span><span class='ectt-0800'> (*unlocked_ioctl) (</span><span id='textcolor293'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> file *, </span><span id='textcolor294'><span class='ectt-0800'>unsigned</span></span><span class='ectt-0800'> </span><span id='textcolor295'><span class='ectt-0800'>int</span></span><span class='ectt-0800'>, </span><span id='textcolor296'><span class='ectt-0800'>unsigned</span></span><span class='ectt-0800'> </span><span id='textcolor297'><span class='ectt-0800'>long</span></span><span class='ectt-0800'>);</span>
|
|
<a id='x1-27066r13'></a><span class='ecrm-0500'>13</span><span class='ectt-0800'> </span><span id='textcolor298'><span class='ectt-0800'>long</span></span><span class='ectt-0800'> (*compat_ioctl) (</span><span id='textcolor299'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> file *, </span><span id='textcolor300'><span class='ectt-0800'>unsigned</span></span><span class='ectt-0800'> </span><span id='textcolor301'><span class='ectt-0800'>int</span></span><span class='ectt-0800'>, </span><span id='textcolor302'><span class='ectt-0800'>unsigned</span></span><span class='ectt-0800'> </span><span id='textcolor303'><span class='ectt-0800'>long</span></span><span class='ectt-0800'>);</span>
|
|
<a id='x1-27068r14'></a><span class='ecrm-0500'>14</span><span class='ectt-0800'> </span><span id='textcolor304'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> (*mmap) (</span><span id='textcolor305'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> file *, </span><span id='textcolor306'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> vm_area_struct *);</span>
|
|
<a id='x1-27070r15'></a><span class='ecrm-0500'>15</span><span class='ectt-0800'> </span><span id='textcolor307'><span class='ectt-0800'>unsigned</span></span><span class='ectt-0800'> </span><span id='textcolor308'><span class='ectt-0800'>long</span></span><span class='ectt-0800'> mmap_supported_flags;</span>
|
|
<a id='x1-27072r16'></a><span class='ecrm-0500'>16</span><span class='ectt-0800'> </span><span id='textcolor309'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> (*open) (</span><span id='textcolor310'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> inode *, </span><span id='textcolor311'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> file *);</span>
|
|
<a id='x1-27074r17'></a><span class='ecrm-0500'>17</span><span class='ectt-0800'> </span><span id='textcolor312'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> (*flush) (</span><span id='textcolor313'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> file *, fl_owner_t id);</span>
|
|
<a id='x1-27076r18'></a><span class='ecrm-0500'>18</span><span class='ectt-0800'> </span><span id='textcolor314'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> (*release) (</span><span id='textcolor315'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> inode *, </span><span id='textcolor316'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> file *);</span>
|
|
<a id='x1-27078r19'></a><span class='ecrm-0500'>19</span><span class='ectt-0800'> </span><span id='textcolor317'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> (*fsync) (</span><span id='textcolor318'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> file *, loff_t, loff_t, </span><span id='textcolor319'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> datasync);</span>
|
|
<a id='x1-27080r20'></a><span class='ecrm-0500'>20</span><span class='ectt-0800'> </span><span id='textcolor320'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> (*fasync) (</span><span id='textcolor321'><span class='ectt-0800'>int</span></span><span class='ectt-0800'>, </span><span id='textcolor322'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> file *, </span><span id='textcolor323'><span class='ectt-0800'>int</span></span><span class='ectt-0800'>);</span>
|
|
<a id='x1-27082r21'></a><span class='ecrm-0500'>21</span><span class='ectt-0800'> </span><span id='textcolor324'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> (*lock) (</span><span id='textcolor325'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> file *, </span><span id='textcolor326'><span class='ectt-0800'>int</span></span><span class='ectt-0800'>, </span><span id='textcolor327'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> file_lock *);</span>
|
|
<a id='x1-27084r22'></a><span class='ecrm-0500'>22</span><span class='ectt-0800'> </span><span id='textcolor328'><span class='ectt-0800'>ssize_t</span></span><span class='ectt-0800'> (*sendpage) (</span><span id='textcolor329'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> file *, </span><span id='textcolor330'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> page *, </span><span id='textcolor331'><span class='ectt-0800'>int</span></span><span class='ectt-0800'>, </span><span id='textcolor332'><span class='ectt-0800'>size_t</span></span><span class='ectt-0800'>, loff_t *, </span><span id='textcolor333'><span class='ectt-0800'>int</span></span><span class='ectt-0800'>);</span>
|
|
<a id='x1-27086r23'></a><span class='ecrm-0500'>23</span><span class='ectt-0800'> </span><span id='textcolor334'><span class='ectt-0800'>unsigned</span></span><span class='ectt-0800'> long (*get_unmapped_area)(</span><span id='textcolor335'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> file *, </span><span id='textcolor336'><span class='ectt-0800'>unsigned</span></span><span class='ectt-0800'> </span><span id='textcolor337'><span class='ectt-0800'>long</span></span><span class='ectt-0800'>, </span><span id='textcolor338'><span class='ectt-0800'>unsigned</span></span><span class='ectt-0800'> </span><span id='textcolor339'><span class='ectt-0800'>long</span></span><span class='ectt-0800'>, </span><span id='textcolor340'><span class='ectt-0800'>unsigned</span></span><span class='ectt-0800'> </span><span id='textcolor341'><span class='ectt-0800'>long</span></span><span class='ectt-0800'>, </span><span id='textcolor342'><span class='ectt-0800'>unsigned</span></span><span class='ectt-0800'> </span><span id='textcolor343'><span class='ectt-0800'>long</span></span><span class='ectt-0800'>);</span>
|
|
<a id='x1-27088r24'></a><span class='ecrm-0500'>24</span><span class='ectt-0800'> </span><span id='textcolor344'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> (*check_flags)(</span><span id='textcolor345'><span class='ectt-0800'>int</span></span><span class='ectt-0800'>);</span>
|
|
<a id='x1-27090r25'></a><span class='ecrm-0500'>25</span><span class='ectt-0800'> </span><span id='textcolor346'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> (*flock) (</span><span id='textcolor347'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> file *, </span><span id='textcolor348'><span class='ectt-0800'>int</span></span><span class='ectt-0800'>, </span><span id='textcolor349'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> file_lock *);</span>
|
|
<a id='x1-27092r26'></a><span class='ecrm-0500'>26</span><span class='ectt-0800'> </span><span id='textcolor350'><span class='ectt-0800'>ssize_t</span></span><span class='ectt-0800'> (*splice_write)(</span><span id='textcolor351'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> pipe_inode_info *, </span><span id='textcolor352'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> file *, loff_t *, </span><span id='textcolor353'><span class='ectt-0800'>size_t</span></span><span class='ectt-0800'>, </span><span id='textcolor354'><span class='ectt-0800'>unsigned</span></span><span class='ectt-0800'> </span><span id='textcolor355'><span class='ectt-0800'>int</span></span><span class='ectt-0800'>);</span>
|
|
<a id='x1-27094r27'></a><span class='ecrm-0500'>27</span><span class='ectt-0800'> </span><span id='textcolor356'><span class='ectt-0800'>ssize_t</span></span><span class='ectt-0800'> (*splice_read)(</span><span id='textcolor357'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> file *, loff_t *, </span><span id='textcolor358'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> pipe_inode_info *, </span><span id='textcolor359'><span class='ectt-0800'>size_t</span></span><span class='ectt-0800'>, </span><span id='textcolor360'><span class='ectt-0800'>unsigned</span></span><span class='ectt-0800'> </span><span id='textcolor361'><span class='ectt-0800'>int</span></span><span class='ectt-0800'>);</span>
|
|
<a id='x1-27096r28'></a><span class='ecrm-0500'>28</span><span class='ectt-0800'> </span><span id='textcolor362'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> (*setlease)(</span><span id='textcolor363'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> file *, </span><span id='textcolor364'><span class='ectt-0800'>long</span></span><span class='ectt-0800'>, </span><span id='textcolor365'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> file_lock **, </span><span id='textcolor366'><span class='ectt-0800'>void</span></span><span class='ectt-0800'> **);</span>
|
|
<a id='x1-27098r29'></a><span class='ecrm-0500'>29</span><span class='ectt-0800'> </span><span id='textcolor367'><span class='ectt-0800'>long</span></span><span class='ectt-0800'> (*fallocate)(</span><span id='textcolor368'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> file *file, </span><span id='textcolor369'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> mode, loff_t offset,</span>
|
|
<a id='x1-27100r30'></a><span class='ecrm-0500'>30</span><span class='ectt-0800'> loff_t len);</span>
|
|
<a id='x1-27102r31'></a><span class='ecrm-0500'>31</span><span class='ectt-0800'> </span><span id='textcolor370'><span class='ectt-0800'>void</span></span><span class='ectt-0800'> (*show_fdinfo)(</span><span id='textcolor371'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> seq_file *m, </span><span id='textcolor372'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> file *f);</span>
|
|
<a id='x1-27104r32'></a><span class='ecrm-0500'>32</span><span class='ectt-0800'> </span><span id='textcolor373'><span class='ectt-0800'>ssize_t</span></span><span class='ectt-0800'> (*copy_file_range)(</span><span id='textcolor374'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> file *, loff_t, </span><span id='textcolor375'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> file *,</span>
|
|
<a id='x1-27106r33'></a><span class='ecrm-0500'>33</span><span class='ectt-0800'> loff_t, </span><span id='textcolor376'><span class='ectt-0800'>size_t</span></span><span class='ectt-0800'>, </span><span id='textcolor377'><span class='ectt-0800'>unsigned</span></span><span class='ectt-0800'> </span><span id='textcolor378'><span class='ectt-0800'>int</span></span><span class='ectt-0800'>);</span>
|
|
<a id='x1-27108r34'></a><span class='ecrm-0500'>34</span><span class='ectt-0800'> loff_t (*remap_file_range)(</span><span id='textcolor379'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> file *file_in, loff_t pos_in,</span>
|
|
<a id='x1-27110r35'></a><span class='ecrm-0500'>35</span><span class='ectt-0800'> </span><span id='textcolor380'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> file *file_out, loff_t pos_out,</span>
|
|
<a id='x1-27112r36'></a><span class='ecrm-0500'>36</span><span class='ectt-0800'> loff_t len, </span><span id='textcolor381'><span class='ectt-0800'>unsigned</span></span><span class='ectt-0800'> </span><span id='textcolor382'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> remap_flags);</span>
|
|
<a id='x1-27114r37'></a><span class='ecrm-0500'>37</span><span class='ectt-0800'> </span><span id='textcolor383'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> (*fadvise)(</span><span id='textcolor384'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> file *, loff_t, loff_t, </span><span id='textcolor385'><span class='ectt-0800'>int</span></span><span class='ectt-0800'>);</span>
|
|
<a id='x1-27116r38'></a><span class='ecrm-0500'>38</span><span class='ectt-0800'>} __randomize_layout;</span></pre>
|
|
<!-- l. 804 --><p class='indent'> Some operations are not implemented by a driver. For example, a driver that handles
|
|
a video card will not need to read from a directory structure. The corresponding entries
|
|
in the <code> <span class='ectt-1000'>file_operations</span>
|
|
</code> structure should be set to <code> <span class='ectt-1000'>NULL</span>
|
|
</code>.
|
|
</p><!-- l. 808 --><p class='indent'> There is a gcc extension that makes assigning to this structure more convenient.
|
|
You will see it in modern drivers, and may catch you by surprise. This is what the
|
|
new way of assigning to the structure looks like:
|
|
</p><!-- l. 1 --><p class='indent'>
|
|
|
|
|
|
|
|
</p>
|
|
<pre class='fancyvrb' id='fancyvrb33'><a id='x1-27126r1'></a><span class='ecrm-0500'>1</span><span id='textcolor386'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> file_operations fops = {</span>
|
|
<a id='x1-27128r2'></a><span class='ecrm-0500'>2</span><span class='ectt-0800'> read: device_read,</span>
|
|
<a id='x1-27130r3'></a><span class='ecrm-0500'>3</span><span class='ectt-0800'> write: device_write,</span>
|
|
<a id='x1-27132r4'></a><span class='ecrm-0500'>4</span><span class='ectt-0800'> open: device_open,</span>
|
|
<a id='x1-27134r5'></a><span class='ecrm-0500'>5</span><span class='ectt-0800'> release: device_release</span>
|
|
<a id='x1-27136r6'></a><span class='ecrm-0500'>6</span><span class='ectt-0800'>};</span></pre>
|
|
<!-- l. 821 --><p class='indent'> However, there is also a C99 way of assigning to elements of a structure,
|
|
<a href='https://gcc.gnu.org/onlinedocs/gcc/Designated-Inits.html'>designated initializers</a>, and this is definitely preferred over using the GNU extension.
|
|
You should use this syntax in case someone wants to port your driver. It will help
|
|
with compatibility:
|
|
</p><!-- l. 1 --><p class='indent'>
|
|
</p>
|
|
<pre class='fancyvrb' id='fancyvrb34'><a id='x1-27144r1'></a><span class='ecrm-0500'>1</span><span id='textcolor387'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> file_operations fops = {</span>
|
|
<a id='x1-27146r2'></a><span class='ecrm-0500'>2</span><span class='ectt-0800'> .read = device_read,</span>
|
|
<a id='x1-27148r3'></a><span class='ecrm-0500'>3</span><span class='ectt-0800'> .write = device_write,</span>
|
|
<a id='x1-27150r4'></a><span class='ecrm-0500'>4</span><span class='ectt-0800'> .open = device_open,</span>
|
|
<a id='x1-27152r5'></a><span class='ecrm-0500'>5</span><span class='ectt-0800'> .release = device_release</span>
|
|
<a id='x1-27154r6'></a><span class='ecrm-0500'>6</span><span class='ectt-0800'>};</span></pre>
|
|
<!-- l. 834 --><p class='indent'> The meaning is clear, and you should be aware that any member of
|
|
the structure which you do not explicitly assign will be initialized to
|
|
<code> <span class='ectt-1000'>NULL</span>
|
|
</code> by gcc.
|
|
</p><!-- l. 836 --><p class='indent'> An instance of <code> <span id='textcolor388'><span class='ectt-1000'>struct</span></span><span class='ectt-1000'> file_operations</span>
|
|
</code> containing pointers to functions that are used to implement
|
|
<code> <span class='ectt-1000'>read</span>
|
|
</code>, <code> <span class='ectt-1000'>write</span>
|
|
</code>, <code> <span class='ectt-1000'>open</span>
|
|
</code>, … system calls is commonly named <code> <span class='ectt-1000'>fops</span>
|
|
</code>.
|
|
</p><!-- l. 838 --><p class='indent'> Since Linux v5.6, the <code> <span class='ectt-1000'>proc_ops</span>
|
|
</code> structure was introduced to replace the use of the
|
|
<code> <span class='ectt-1000'>file_operations</span>
|
|
</code> structure when registering proc handlers.
|
|
</p><!-- l. 840 --><p class='noindent'>
|
|
</p>
|
|
<h4 class='subsectionHead' id='the-file-structure'><span class='titlemark'>6.2 </span> <a id='x1-280006.2'></a>The file structure</h4>
|
|
<!-- l. 843 --><p class='noindent'>Each device is represented in the kernel by a file structure, which is defined
|
|
in <a href='https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/tree/include/linux/fs.h'>include/linux/fs.h</a>. Be aware that a file is a kernel level structure and
|
|
never appears in a user space program. It is not the same thing as a
|
|
<code> <span id='textcolor389'><span class='ectt-1000'>FILE</span></span>
|
|
</code>, which is defined by glibc and would never appear in a kernel space
|
|
function. Also, its name is a bit misleading; it represents an abstract open
|
|
‘file’, not a file on a disk, which is represented by a structure named
|
|
<code> <span class='ectt-1000'>inode</span>
|
|
</code>.
|
|
</p><!-- l. 848 --><p class='indent'> An instance of struct file is commonly named
|
|
<code> <span class='ectt-1000'>filp</span>
|
|
</code>. You’ll also see it referred to as a struct file object. Resist the temptation.
|
|
</p><!-- l. 852 --><p class='indent'> Go ahead and look at the definition of file. Most of the entries you see, like struct
|
|
dentry are not used by device drivers, and you can ignore them. This is because
|
|
drivers do not fill file directly; they only use structures contained in file which are
|
|
created elsewhere.
|
|
|
|
|
|
|
|
</p><!-- l. 856 --><p class='noindent'>
|
|
</p>
|
|
<h4 class='subsectionHead' id='registering-a-device'><span class='titlemark'>6.3 </span> <a id='x1-290006.3'></a>Registering A Device</h4>
|
|
<!-- l. 858 --><p class='noindent'>As discussed earlier, char devices are accessed through device files, usually located in
|
|
<span class='obeylines-h'><span class='verb'><span class='ectt-1000'>/dev</span></span></span>. This is by convention. When writing a driver, it is OK to put the
|
|
device file in your current directory. Just make sure you place it in <span class='obeylines-h'><span class='verb'><span class='ectt-1000'>/dev</span></span></span> for a
|
|
production driver. The major number tells you which driver handles which
|
|
device file. The minor number is used only by the driver itself to differentiate
|
|
which device it is operating on, just in case the driver handles more than one
|
|
device.
|
|
</p><!-- l. 864 --><p class='indent'> Adding a driver to your system means registering it with the kernel. This is synonymous
|
|
with assigning it a major number during the module’s initialization. You do this by
|
|
using the <code> <span class='ectt-1000'>register_chrdev</span>
|
|
</code> function, defined by <a href='https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/tree/include/linux/fs.h'>include/linux/fs.h</a>.
|
|
</p><!-- l. 1 --><p class='indent'>
|
|
</p>
|
|
<pre class='fancyvrb' id='fancyvrb35'><a id='x1-29004r1'></a><span class='ecrm-0500'>1</span><span id='textcolor390'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> register_chrdev(</span><span id='textcolor391'><span class='ectt-0800'>unsigned</span></span><span class='ectt-0800'> </span><span id='textcolor392'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> major, </span><span id='textcolor393'><span class='ectt-0800'>const</span></span><span class='ectt-0800'> </span><span id='textcolor394'><span class='ectt-0800'>char</span></span><span class='ectt-0800'> *name, </span><span id='textcolor395'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> file_operations *fops);</span></pre>
|
|
<!-- l. 872 --><p class='indent'> where unsigned int major is the major number you want to request,
|
|
<code> <span id='textcolor396'><span class='ectt-1000'>const</span></span><span class='ectt-1000'> </span><span id='textcolor397'><span class='ectt-1000'>char</span></span><span class='ectt-1000'> *name</span>
|
|
</code> is the name of the device as it will appear in <span class='obeylines-h'><span class='verb'><span class='ectt-1000'>/proc/devices</span></span></span> and
|
|
<code> <span id='textcolor398'><span class='ectt-1000'>struct</span></span><span class='ectt-1000'> file_operations *fops</span>
|
|
</code> is a pointer to the <code> <span class='ectt-1000'>file_operations</span>
|
|
</code> table for your driver. A negative return value means the
|
|
registration failed. Note that we didn’t pass the minor number to
|
|
<code> <span class='ectt-1000'>register_chrdev</span>
|
|
</code>. That is because the kernel doesn’t care about the minor number; only our driver
|
|
uses it.
|
|
</p><!-- l. 876 --><p class='indent'> Now the question is, how do you get a major number without hijacking
|
|
one that’s already in use? The easiest way would be to look through
|
|
<a href='https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/tree/Documentation/admin-guide/devices.txt'>Documentation/admin-guide/devices.txt</a> and pick an unused one. That is a bad way
|
|
of doing things because you will never be sure if the number you picked will be
|
|
assigned later. The answer is that you can ask the kernel to assign you a dynamic
|
|
major number.
|
|
</p><!-- l. 881 --><p class='indent'> If you pass a major number of 0 to <code> <span class='ectt-1000'>register_chrdev</span>
|
|
</code>, the return value will be the dynamically allocated major number. The
|
|
downside is that you can not make a device file in advance, since you do not
|
|
know what the major number will be. There are a couple of ways to do
|
|
this. First, the driver itself can print the newly assigned number and we
|
|
can make the device file by hand. Second, the newly registered device will
|
|
have an entry in <span class='obeylines-h'><span class='verb'><span class='ectt-1000'>/proc/devices</span></span></span>, and we can either make the device file by
|
|
hand or write a shell script to read the file in and make the device file. The
|
|
third method is that we can have our driver make the device file using the
|
|
<code> <span class='ectt-1000'>device_create</span>
|
|
|
|
|
|
|
|
</code> function after a successful registration and
|
|
<code> <span class='ectt-1000'>device_destroy</span>
|
|
</code> during the call to <code> <span class='ectt-1000'>cleanup_module</span>
|
|
</code>.
|
|
</p><!-- l. 888 --><p class='noindent'>
|
|
</p>
|
|
<h4 class='subsectionHead' id='unregistering-a-device'><span class='titlemark'>6.4 </span> <a id='x1-300006.4'></a>Unregistering A Device</h4>
|
|
<!-- l. 890 --><p class='noindent'>We can not allow the kernel module to be
|
|
<code> <span class='ectt-1000'>rmmod</span>
|
|
</code>’ed whenever root feels like it. If the device file is opened by a process and then we
|
|
remove the kernel module, using the file would cause a call to the memory location
|
|
where the appropriate function (read/write) used to be. If we are lucky, no
|
|
other code was loaded there, and we’ll get an ugly error message. If we are
|
|
unlucky, another kernel module was loaded into the same location, which
|
|
means a jump into the middle of another function within the kernel. The
|
|
results of this would be impossible to predict, but they can not be very
|
|
positive.
|
|
</p><!-- l. 896 --><p class='indent'> Normally, when you do not want to allow something, you return an error code
|
|
(a negative number) from the function which is supposed to do it. With
|
|
<code> <span class='ectt-1000'>cleanup_module</span>
|
|
</code> that’s impossible because it is a void function. However, there is a counter
|
|
which keeps track of how many processes are using your module. You
|
|
can see what its value is by looking at the 3rd field with the command
|
|
<code> <span class='ectt-1000'>cat /proc/modules</span>
|
|
</code> or <code> <span class='ectt-1000'>sudo lsmod</span>
|
|
</code>. If this number isn’t zero, <code> <span class='ectt-1000'>rmmod</span>
|
|
</code> will fail. Note that you do not have to check the counter within
|
|
<code> <span class='ectt-1000'>cleanup_module</span>
|
|
</code> because the check will be performed for you by the system call
|
|
<code> <span class='ectt-1000'>sys_delete_module</span>
|
|
</code>, defined in <a href='https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/tree/include/linux/syscalls.h'>include/linux/syscalls.h</a>. You should not use this counter directly, but
|
|
there are functions defined in <a href='https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/tree/include/linux/module.h'>include/linux/module.h</a> which let you increase,
|
|
decrease and display this counter:
|
|
</p>
|
|
<ul class='itemize1'>
|
|
<li class='itemize'><code> <span class='ectt-1000'>try_module_get(THIS_MODULE)</span>
|
|
</code>: Increment the reference count of current module.
|
|
</li>
|
|
<li class='itemize'><code> <span class='ectt-1000'>module_put(THIS_MODULE)</span>
|
|
</code>: Decrement the reference count of current module.
|
|
</li>
|
|
<li class='itemize'><code> <span class='ectt-1000'>module_refcount(THIS_MODULE)</span>
|
|
</code>: Return the value of reference count of current module.</li></ul>
|
|
<!-- l. 910 --><p class='indent'> It is important to keep the counter accurate; if you ever do lose track of the
|
|
correct usage count, you will never be able to unload the module; it’s now reboot
|
|
time, boys and girls. This is bound to happen to you sooner or later during a
|
|
module’s development.
|
|
</p><!-- l. 913 --><p class='noindent'>
|
|
</p>
|
|
<h4 class='subsectionHead' id='chardevc'><span class='titlemark'>6.5 </span> <a id='x1-310006.5'></a>chardev.c</h4>
|
|
<!-- l. 915 --><p class='noindent'>The next code sample creates a char driver named <span class='obeylines-h'><span class='verb'><span class='ectt-1000'>chardev</span></span></span>. You can cat its device
|
|
file.
|
|
</p><!-- l. 1 --><p class='indent'>
|
|
</p>
|
|
<pre class='fancyvrb' id='fancyvrb36'><a id='x1-31003r1'></a><span class='ecrm-0500'>1</span><span class='ectt-1000'>cat /proc/devices</span></pre>
|
|
<!-- l. 922 --><p class='indent'> (or open the file with a program) and the driver will put the number of times the
|
|
device file has been read from into the file. We do not support writing to the file (like
|
|
<code> <span class='ectt-1000'>echo </span><span id='textcolor399'><span class='ectt-1000'>"hi"</span></span><span class='ectt-1000'> > /dev/hello</span>
|
|
</code>), but catch these attempts and tell the user that the operation is not supported.
|
|
Don’t worry if you don’t see what we do with the data we read into the buffer; we
|
|
don’t do much with it. We simply read in the data and print a message
|
|
acknowledging that we received it.
|
|
</p><!-- l. 927 --><p class='indent'> In the multiple-threaded environment, without any protection, concurrent access
|
|
to the same memory may lead to the race condition, and will not preserve
|
|
the performance. In the kernel module, this problem may happen due to
|
|
multiple instances accessing the shared resources. Therefore, a solution is to
|
|
enforce the exclusive access. We use atomic Compare-And-Swap (CAS),
|
|
the single atomic operation, to determine whether the file is currently open
|
|
by someone. CAS compares the contents of a memory loaction with the
|
|
expected value and, only if they are the same, modifies the contents of that
|
|
memory location to the desired value. See more concurrency details in the <a href='#avoiding-collisions-and-deadlocks'>12<!-- tex4ht:ref: sec:synchronization --></a>
|
|
section.
|
|
</p><!-- l. 1 --><p class='indent'>
|
|
</p>
|
|
<pre class='fancyvrb' id='fancyvrb37'><a id='x1-31006r1'></a><span class='ecrm-0500'>1</span><span id='textcolor400'><span class='ectt-0800'>/*</span></span>
|
|
<a id='x1-31008r2'></a><span class='ecrm-0500'>2</span><span id='textcolor401'><span class='ectt-0800'> * chardev.c: Creates a read-only char device that says how many times</span></span>
|
|
<a id='x1-31010r3'></a><span class='ecrm-0500'>3</span><span id='textcolor402'><span class='ectt-0800'> * you have read from the dev file</span></span>
|
|
<a id='x1-31012r4'></a><span class='ecrm-0500'>4</span><span id='textcolor403'><span class='ectt-0800'> */</span></span>
|
|
<a id='x1-31014r5'></a><span class='ecrm-0500'>5</span>
|
|
<a id='x1-31016r6'></a><span class='ecrm-0500'>6</span><span id='textcolor404'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor405'><span class='ectt-0800'><linux/cdev.h></span></span>
|
|
<a id='x1-31018r7'></a><span class='ecrm-0500'>7</span><span id='textcolor406'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor407'><span class='ectt-0800'><linux/delay.h></span></span>
|
|
<a id='x1-31020r8'></a><span class='ecrm-0500'>8</span><span id='textcolor408'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor409'><span class='ectt-0800'><linux/device.h></span></span>
|
|
<a id='x1-31022r9'></a><span class='ecrm-0500'>9</span><span id='textcolor410'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor411'><span class='ectt-0800'><linux/fs.h></span></span>
|
|
<a id='x1-31024r10'></a><span class='ecrm-0500'>10</span><span id='textcolor412'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor413'><span class='ectt-0800'><linux/init.h></span></span>
|
|
<a id='x1-31026r11'></a><span class='ecrm-0500'>11</span><span id='textcolor414'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor415'><span class='ectt-0800'><linux/irq.h></span></span>
|
|
<a id='x1-31028r12'></a><span class='ecrm-0500'>12</span><span id='textcolor416'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor417'><span class='ectt-0800'><linux/kernel.h></span></span>
|
|
<a id='x1-31030r13'></a><span class='ecrm-0500'>13</span><span id='textcolor418'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor419'><span class='ectt-0800'><linux/module.h></span></span>
|
|
<a id='x1-31032r14'></a><span class='ecrm-0500'>14</span><span id='textcolor420'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor421'><span class='ectt-0800'><linux/poll.h></span></span>
|
|
<a id='x1-31034r15'></a><span class='ecrm-0500'>15</span>
|
|
<a id='x1-31036r16'></a><span class='ecrm-0500'>16</span><span id='textcolor422'><span class='ectt-0800'>/* Prototypes - this would normally go in a .h file */</span></span>
|
|
<a id='x1-31038r17'></a><span class='ecrm-0500'>17</span><span id='textcolor423'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor424'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> device_open(</span><span id='textcolor425'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> inode *, </span><span id='textcolor426'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> file *);</span>
|
|
<a id='x1-31040r18'></a><span class='ecrm-0500'>18</span><span id='textcolor427'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor428'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> device_release(</span><span id='textcolor429'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> inode *, </span><span id='textcolor430'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> file *);</span>
|
|
<a id='x1-31042r19'></a><span class='ecrm-0500'>19</span><span id='textcolor431'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor432'><span class='ectt-0800'>ssize_t</span></span><span class='ectt-0800'> device_read(</span><span id='textcolor433'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> file *, </span><span id='textcolor434'><span class='ectt-0800'>char</span></span><span class='ectt-0800'> __user *, </span><span id='textcolor435'><span class='ectt-0800'>size_t</span></span><span class='ectt-0800'>, loff_t *);</span>
|
|
<a id='x1-31044r20'></a><span class='ecrm-0500'>20</span><span id='textcolor436'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor437'><span class='ectt-0800'>ssize_t</span></span><span class='ectt-0800'> device_write(</span><span id='textcolor438'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> file *, </span><span id='textcolor439'><span class='ectt-0800'>const</span></span><span class='ectt-0800'> </span><span id='textcolor440'><span class='ectt-0800'>char</span></span><span class='ectt-0800'> __user *, </span><span id='textcolor441'><span class='ectt-0800'>size_t</span></span><span class='ectt-0800'>,</span>
|
|
<a id='x1-31046r21'></a><span class='ecrm-0500'>21</span><span class='ectt-0800'> loff_t *);</span>
|
|
<a id='x1-31048r22'></a><span class='ecrm-0500'>22</span>
|
|
<a id='x1-31050r23'></a><span class='ecrm-0500'>23</span><span id='textcolor442'><span class='ectt-0800'>#define SUCCESS 0</span></span>
|
|
<a id='x1-31052r24'></a><span class='ecrm-0500'>24</span><span id='textcolor443'><span class='ectt-0800'>#define DEVICE_NAME "chardev" </span></span><span id='textcolor444'><span class='ectt-0800'>/* Dev name as it appears in /proc/devices */</span></span>
|
|
<a id='x1-31054r25'></a><span class='ecrm-0500'>25</span><span id='textcolor445'><span class='ectt-0800'>#define BUF_LEN 80 </span></span><span id='textcolor446'><span class='ectt-0800'>/* Max length of the message from the device */</span></span>
|
|
<a id='x1-31056r26'></a><span class='ecrm-0500'>26</span>
|
|
<a id='x1-31058r27'></a><span class='ecrm-0500'>27</span><span id='textcolor447'><span class='ectt-0800'>/* Global variables are declared as static, so are global within the file. */</span></span>
|
|
<a id='x1-31060r28'></a><span class='ecrm-0500'>28</span>
|
|
<a id='x1-31062r29'></a><span class='ecrm-0500'>29</span><span id='textcolor448'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor449'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> major; </span><span id='textcolor450'><span class='ectt-0800'>/* major number assigned to our device driver */</span></span>
|
|
<a id='x1-31064r30'></a><span class='ecrm-0500'>30</span><span id='textcolor451'><span class='ectt-0800'>/* Is device open? Used to prevent multiple access to device */</span></span>
|
|
<a id='x1-31066r31'></a><span class='ecrm-0500'>31</span><span id='textcolor452'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> atomic_t already_open = ATOMIC_INIT(0);</span>
|
|
<a id='x1-31068r32'></a><span class='ecrm-0500'>32</span><span id='textcolor453'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor454'><span class='ectt-0800'>char</span></span><span class='ectt-0800'> msg[BUF_LEN]; </span><span id='textcolor455'><span class='ectt-0800'>/* The msg the device will give when asked */</span></span>
|
|
<a id='x1-31070r33'></a><span class='ecrm-0500'>33</span><span id='textcolor456'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor457'><span class='ectt-0800'>char</span></span><span class='ectt-0800'> *msg_ptr;</span>
|
|
<a id='x1-31072r34'></a><span class='ecrm-0500'>34</span>
|
|
<a id='x1-31074r35'></a><span class='ecrm-0500'>35</span><span id='textcolor458'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor459'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> class *cls;</span>
|
|
<a id='x1-31076r36'></a><span class='ecrm-0500'>36</span>
|
|
<a id='x1-31078r37'></a><span class='ecrm-0500'>37</span><span id='textcolor460'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor461'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> file_operations chardev_fops = {</span>
|
|
<a id='x1-31080r38'></a><span class='ecrm-0500'>38</span><span class='ectt-0800'> .read = device_read,</span>
|
|
<a id='x1-31082r39'></a><span class='ecrm-0500'>39</span><span class='ectt-0800'> .write = device_write,</span>
|
|
<a id='x1-31084r40'></a><span class='ecrm-0500'>40</span><span class='ectt-0800'> .open = device_open,</span>
|
|
<a id='x1-31086r41'></a><span class='ecrm-0500'>41</span><span class='ectt-0800'> .release = device_release,</span>
|
|
<a id='x1-31088r42'></a><span class='ecrm-0500'>42</span><span class='ectt-0800'>};</span>
|
|
<a id='x1-31090r43'></a><span class='ecrm-0500'>43</span>
|
|
<a id='x1-31092r44'></a><span class='ecrm-0500'>44</span><span id='textcolor462'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor463'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> __init chardev_init(</span><span id='textcolor464'><span class='ectt-0800'>void</span></span><span class='ectt-0800'>)</span>
|
|
<a id='x1-31094r45'></a><span class='ecrm-0500'>45</span><span class='ectt-0800'>{</span>
|
|
<a id='x1-31096r46'></a><span class='ecrm-0500'>46</span><span class='ectt-0800'> major = register_chrdev(0, DEVICE_NAME, &chardev_fops);</span>
|
|
<a id='x1-31098r47'></a><span class='ecrm-0500'>47</span>
|
|
<a id='x1-31100r48'></a><span class='ecrm-0500'>48</span><span class='ectt-0800'> </span><span id='textcolor465'><span class='ectt-0800'>if</span></span><span class='ectt-0800'> (major < 0) {</span>
|
|
<a id='x1-31102r49'></a><span class='ecrm-0500'>49</span><span class='ectt-0800'> pr_alert(</span><span id='textcolor466'><span class='ectt-0800'>"Registering char device failed with %d</span></span><span id='textcolor467'><span class='ectt-0800'>\n</span></span><span id='textcolor468'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>, major);</span>
|
|
<a id='x1-31104r50'></a><span class='ecrm-0500'>50</span><span class='ectt-0800'> </span><span id='textcolor469'><span class='ectt-0800'>return</span></span><span class='ectt-0800'> major;</span>
|
|
<a id='x1-31106r51'></a><span class='ecrm-0500'>51</span><span class='ectt-0800'> }</span>
|
|
<a id='x1-31108r52'></a><span class='ecrm-0500'>52</span>
|
|
<a id='x1-31110r53'></a><span class='ecrm-0500'>53</span><span class='ectt-0800'> pr_info(</span><span id='textcolor470'><span class='ectt-0800'>"I was assigned major number %d.</span></span><span id='textcolor471'><span class='ectt-0800'>\n</span></span><span id='textcolor472'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>, major);</span>
|
|
<a id='x1-31112r54'></a><span class='ecrm-0500'>54</span>
|
|
<a id='x1-31114r55'></a><span class='ecrm-0500'>55</span><span class='ectt-0800'> cls = class_create(THIS_MODULE, DEVICE_NAME);</span>
|
|
<a id='x1-31116r56'></a><span class='ecrm-0500'>56</span><span class='ectt-0800'> device_create(cls, NULL, MKDEV(major, 0), NULL, DEVICE_NAME);</span>
|
|
<a id='x1-31118r57'></a><span class='ecrm-0500'>57</span>
|
|
<a id='x1-31120r58'></a><span class='ecrm-0500'>58</span><span class='ectt-0800'> pr_info(</span><span id='textcolor473'><span class='ectt-0800'>"Device created on /dev/%s</span></span><span id='textcolor474'><span class='ectt-0800'>\n</span></span><span id='textcolor475'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>, DEVICE_NAME);</span>
|
|
<a id='x1-31122r59'></a><span class='ecrm-0500'>59</span>
|
|
<a id='x1-31124r60'></a><span class='ecrm-0500'>60</span><span class='ectt-0800'> </span><span id='textcolor476'><span class='ectt-0800'>return</span></span><span class='ectt-0800'> SUCCESS;</span>
|
|
<a id='x1-31126r61'></a><span class='ecrm-0500'>61</span><span class='ectt-0800'>}</span>
|
|
<a id='x1-31128r62'></a><span class='ecrm-0500'>62</span>
|
|
<a id='x1-31130r63'></a><span class='ecrm-0500'>63</span><span id='textcolor477'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor478'><span class='ectt-0800'>void</span></span><span class='ectt-0800'> __exit chardev_exit(</span><span id='textcolor479'><span class='ectt-0800'>void</span></span><span class='ectt-0800'>)</span>
|
|
<a id='x1-31132r64'></a><span class='ecrm-0500'>64</span><span class='ectt-0800'>{</span>
|
|
<a id='x1-31134r65'></a><span class='ecrm-0500'>65</span><span class='ectt-0800'> device_destroy(cls, MKDEV(major, 0));</span>
|
|
<a id='x1-31136r66'></a><span class='ecrm-0500'>66</span><span class='ectt-0800'> class_destroy(cls);</span>
|
|
<a id='x1-31138r67'></a><span class='ecrm-0500'>67</span>
|
|
<a id='x1-31140r68'></a><span class='ecrm-0500'>68</span><span class='ectt-0800'> </span><span id='textcolor480'><span class='ectt-0800'>/* Unregister the device */</span></span>
|
|
<a id='x1-31142r69'></a><span class='ecrm-0500'>69</span><span class='ectt-0800'> unregister_chrdev(major, DEVICE_NAME);</span>
|
|
<a id='x1-31144r70'></a><span class='ecrm-0500'>70</span><span class='ectt-0800'>}</span>
|
|
<a id='x1-31146r71'></a><span class='ecrm-0500'>71</span>
|
|
<a id='x1-31148r72'></a><span class='ecrm-0500'>72</span><span id='textcolor481'><span class='ectt-0800'>/* Methods */</span></span>
|
|
<a id='x1-31150r73'></a><span class='ecrm-0500'>73</span>
|
|
<a id='x1-31152r74'></a><span class='ecrm-0500'>74</span><span id='textcolor482'><span class='ectt-0800'>/* Called when a process tries to open the device file, like</span></span>
|
|
<a id='x1-31154r75'></a><span class='ecrm-0500'>75</span><span id='textcolor483'><span class='ectt-0800'> * "sudo cat /dev/chardev"</span></span>
|
|
<a id='x1-31156r76'></a><span class='ecrm-0500'>76</span><span id='textcolor484'><span class='ectt-0800'> */</span></span>
|
|
<a id='x1-31158r77'></a><span class='ecrm-0500'>77</span><span id='textcolor485'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor486'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> device_open(</span><span id='textcolor487'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> inode *inode, </span><span id='textcolor488'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> file *file)</span>
|
|
<a id='x1-31160r78'></a><span class='ecrm-0500'>78</span><span class='ectt-0800'>{</span>
|
|
<a id='x1-31162r79'></a><span class='ecrm-0500'>79</span><span class='ectt-0800'> </span><span id='textcolor489'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor490'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> counter = 0;</span>
|
|
<a id='x1-31164r80'></a><span class='ecrm-0500'>80</span>
|
|
<a id='x1-31166r81'></a><span class='ecrm-0500'>81</span><span class='ectt-0800'> </span><span id='textcolor491'><span class='ectt-0800'>if</span></span><span class='ectt-0800'> (atomic_cmpxchg(&already_open, 0, 1))</span>
|
|
<a id='x1-31168r82'></a><span class='ecrm-0500'>82</span><span class='ectt-0800'> </span><span id='textcolor492'><span class='ectt-0800'>return</span></span><span class='ectt-0800'> -EBUSY;</span>
|
|
<a id='x1-31170r83'></a><span class='ecrm-0500'>83</span>
|
|
<a id='x1-31172r84'></a><span class='ecrm-0500'>84</span><span class='ectt-0800'> sprintf(msg, </span><span id='textcolor493'><span class='ectt-0800'>"I already told you %d times Hello world!</span></span><span id='textcolor494'><span class='ectt-0800'>\n</span></span><span id='textcolor495'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>, counter++);</span>
|
|
<a id='x1-31174r85'></a><span class='ecrm-0500'>85</span><span class='ectt-0800'> msg_ptr = msg;</span>
|
|
<a id='x1-31176r86'></a><span class='ecrm-0500'>86</span><span class='ectt-0800'> try_module_get(THIS_MODULE);</span>
|
|
<a id='x1-31178r87'></a><span class='ecrm-0500'>87</span>
|
|
<a id='x1-31180r88'></a><span class='ecrm-0500'>88</span><span class='ectt-0800'> </span><span id='textcolor496'><span class='ectt-0800'>return</span></span><span class='ectt-0800'> SUCCESS;</span>
|
|
<a id='x1-31182r89'></a><span class='ecrm-0500'>89</span><span class='ectt-0800'>}</span>
|
|
<a id='x1-31184r90'></a><span class='ecrm-0500'>90</span>
|
|
<a id='x1-31186r91'></a><span class='ecrm-0500'>91</span><span id='textcolor497'><span class='ectt-0800'>/* Called when a process closes the device file. */</span></span>
|
|
<a id='x1-31188r92'></a><span class='ecrm-0500'>92</span><span id='textcolor498'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor499'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> device_release(</span><span id='textcolor500'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> inode *inode, </span><span id='textcolor501'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> file *file)</span>
|
|
<a id='x1-31190r93'></a><span class='ecrm-0500'>93</span><span class='ectt-0800'>{</span>
|
|
<a id='x1-31192r94'></a><span class='ecrm-0500'>94</span><span class='ectt-0800'> atomic_set(&already_open, 0); </span><span id='textcolor502'><span class='ectt-0800'>/* We</span><span class='tctt-0800'>'</span><span class='ectt-0800'>re now ready for our next caller */</span></span>
|
|
<a id='x1-31194r95'></a><span class='ecrm-0500'>95</span>
|
|
<a id='x1-31196r96'></a><span class='ecrm-0500'>96</span><span class='ectt-0800'> </span><span id='textcolor503'><span class='ectt-0800'>/* Decrement the usage count, or else once you opened the file, you will</span></span>
|
|
<a id='x1-31198r97'></a><span class='ecrm-0500'>97</span><span id='textcolor504'><span class='ectt-0800'> * never get get rid of the module.</span></span>
|
|
<a id='x1-31200r98'></a><span class='ecrm-0500'>98</span><span id='textcolor505'><span class='ectt-0800'> */</span></span>
|
|
<a id='x1-31202r99'></a><span class='ecrm-0500'>99</span><span class='ectt-0800'> module_put(THIS_MODULE);</span>
|
|
<a id='x1-31204r100'></a><span class='ecrm-0500'>100</span>
|
|
<a id='x1-31206r101'></a><span class='ecrm-0500'>101</span><span class='ectt-0800'> </span><span id='textcolor506'><span class='ectt-0800'>return</span></span><span class='ectt-0800'> SUCCESS;</span>
|
|
<a id='x1-31208r102'></a><span class='ecrm-0500'>102</span><span class='ectt-0800'>}</span>
|
|
<a id='x1-31210r103'></a><span class='ecrm-0500'>103</span>
|
|
<a id='x1-31212r104'></a><span class='ecrm-0500'>104</span><span id='textcolor507'><span class='ectt-0800'>/* Called when a process, which already opened the dev file, attempts to</span></span>
|
|
<a id='x1-31214r105'></a><span class='ecrm-0500'>105</span><span id='textcolor508'><span class='ectt-0800'> * read from it.</span></span>
|
|
<a id='x1-31216r106'></a><span class='ecrm-0500'>106</span><span id='textcolor509'><span class='ectt-0800'> */</span></span>
|
|
<a id='x1-31218r107'></a><span class='ecrm-0500'>107</span><span id='textcolor510'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor511'><span class='ectt-0800'>ssize_t</span></span><span class='ectt-0800'> device_read(</span><span id='textcolor512'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> file *filp, </span><span id='textcolor513'><span class='ectt-0800'>/* see include/linux/fs.h */</span></span>
|
|
<a id='x1-31220r108'></a><span class='ecrm-0500'>108</span><span class='ectt-0800'> </span><span id='textcolor514'><span class='ectt-0800'>char</span></span><span class='ectt-0800'> __user *buffer, </span><span id='textcolor515'><span class='ectt-0800'>/* buffer to fill with data */</span></span>
|
|
<a id='x1-31222r109'></a><span class='ecrm-0500'>109</span><span class='ectt-0800'> </span><span id='textcolor516'><span class='ectt-0800'>size_t</span></span><span class='ectt-0800'> length, </span><span id='textcolor517'><span class='ectt-0800'>/* length of the buffer */</span></span>
|
|
<a id='x1-31224r110'></a><span class='ecrm-0500'>110</span><span class='ectt-0800'> loff_t *offset)</span>
|
|
<a id='x1-31226r111'></a><span class='ecrm-0500'>111</span><span class='ectt-0800'>{</span>
|
|
<a id='x1-31228r112'></a><span class='ecrm-0500'>112</span><span class='ectt-0800'> </span><span id='textcolor518'><span class='ectt-0800'>/* Number of bytes actually written to the buffer */</span></span>
|
|
<a id='x1-31230r113'></a><span class='ecrm-0500'>113</span><span class='ectt-0800'> </span><span id='textcolor519'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> bytes_read = 0;</span>
|
|
<a id='x1-31232r114'></a><span class='ecrm-0500'>114</span>
|
|
<a id='x1-31234r115'></a><span class='ecrm-0500'>115</span><span class='ectt-0800'> </span><span id='textcolor520'><span class='ectt-0800'>/* If we are at the end of message, return 0 signifying end of file. */</span></span>
|
|
<a id='x1-31236r116'></a><span class='ecrm-0500'>116</span><span class='ectt-0800'> </span><span id='textcolor521'><span class='ectt-0800'>if</span></span><span class='ectt-0800'> (*msg_ptr == 0)</span>
|
|
<a id='x1-31238r117'></a><span class='ecrm-0500'>117</span><span class='ectt-0800'> </span><span id='textcolor522'><span class='ectt-0800'>return</span></span><span class='ectt-0800'> 0;</span>
|
|
<a id='x1-31240r118'></a><span class='ecrm-0500'>118</span>
|
|
<a id='x1-31242r119'></a><span class='ecrm-0500'>119</span><span class='ectt-0800'> </span><span id='textcolor523'><span class='ectt-0800'>/* Actually put the data into the buffer */</span></span>
|
|
<a id='x1-31244r120'></a><span class='ecrm-0500'>120</span><span class='ectt-0800'> </span><span id='textcolor524'><span class='ectt-0800'>while</span></span><span class='ectt-0800'> (length && *msg_ptr) {</span>
|
|
<a id='x1-31246r121'></a><span class='ecrm-0500'>121</span><span class='ectt-0800'> </span><span id='textcolor525'><span class='ectt-0800'>/* The buffer is in the user data segment, not the kernel</span></span>
|
|
<a id='x1-31248r122'></a><span class='ecrm-0500'>122</span><span id='textcolor526'><span class='ectt-0800'> * segment so "*" assignment won</span><span class='tctt-0800'>'</span><span class='ectt-0800'>t work. We have to use</span></span>
|
|
<a id='x1-31250r123'></a><span class='ecrm-0500'>123</span><span id='textcolor527'><span class='ectt-0800'> * put_user which copies data from the kernel data segment to</span></span>
|
|
<a id='x1-31252r124'></a><span class='ecrm-0500'>124</span><span id='textcolor528'><span class='ectt-0800'> * the user data segment.</span></span>
|
|
<a id='x1-31254r125'></a><span class='ecrm-0500'>125</span><span id='textcolor529'><span class='ectt-0800'> */</span></span>
|
|
<a id='x1-31256r126'></a><span class='ecrm-0500'>126</span><span class='ectt-0800'> put_user(*(msg_ptr++), buffer++);</span>
|
|
<a id='x1-31258r127'></a><span class='ecrm-0500'>127</span>
|
|
<a id='x1-31260r128'></a><span class='ecrm-0500'>128</span><span class='ectt-0800'> length--;</span>
|
|
<a id='x1-31262r129'></a><span class='ecrm-0500'>129</span><span class='ectt-0800'> bytes_read++;</span>
|
|
<a id='x1-31264r130'></a><span class='ecrm-0500'>130</span><span class='ectt-0800'> }</span>
|
|
<a id='x1-31266r131'></a><span class='ecrm-0500'>131</span>
|
|
<a id='x1-31268r132'></a><span class='ecrm-0500'>132</span><span class='ectt-0800'> </span><span id='textcolor530'><span class='ectt-0800'>/* Most read functions return the number of bytes put into the buffer. */</span></span>
|
|
<a id='x1-31270r133'></a><span class='ecrm-0500'>133</span><span class='ectt-0800'> </span><span id='textcolor531'><span class='ectt-0800'>return</span></span><span class='ectt-0800'> bytes_read;</span>
|
|
<a id='x1-31272r134'></a><span class='ecrm-0500'>134</span><span class='ectt-0800'>}</span>
|
|
<a id='x1-31274r135'></a><span class='ecrm-0500'>135</span>
|
|
<a id='x1-31276r136'></a><span class='ecrm-0500'>136</span><span id='textcolor532'><span class='ectt-0800'>/* Called when a process writes to dev file: echo "hi" > /dev/hello */</span></span>
|
|
<a id='x1-31278r137'></a><span class='ecrm-0500'>137</span><span id='textcolor533'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor534'><span class='ectt-0800'>ssize_t</span></span><span class='ectt-0800'> device_write(</span><span id='textcolor535'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> file *filp, </span><span id='textcolor536'><span class='ectt-0800'>const</span></span><span class='ectt-0800'> </span><span id='textcolor537'><span class='ectt-0800'>char</span></span><span class='ectt-0800'> __user *buff,</span>
|
|
<a id='x1-31280r138'></a><span class='ecrm-0500'>138</span><span class='ectt-0800'> </span><span id='textcolor538'><span class='ectt-0800'>size_t</span></span><span class='ectt-0800'> len, loff_t *off)</span>
|
|
<a id='x1-31282r139'></a><span class='ecrm-0500'>139</span><span class='ectt-0800'>{</span>
|
|
<a id='x1-31284r140'></a><span class='ecrm-0500'>140</span><span class='ectt-0800'> pr_alert(</span><span id='textcolor539'><span class='ectt-0800'>"Sorry, this operation is not supported.</span></span><span id='textcolor540'><span class='ectt-0800'>\n</span></span><span id='textcolor541'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>);</span>
|
|
<a id='x1-31286r141'></a><span class='ecrm-0500'>141</span><span class='ectt-0800'> </span><span id='textcolor542'><span class='ectt-0800'>return</span></span><span class='ectt-0800'> -EINVAL;</span>
|
|
<a id='x1-31288r142'></a><span class='ecrm-0500'>142</span><span class='ectt-0800'>}</span>
|
|
<a id='x1-31290r143'></a><span class='ecrm-0500'>143</span>
|
|
<a id='x1-31292r144'></a><span class='ecrm-0500'>144</span><span class='ectt-0800'>module_init(chardev_init);</span>
|
|
<a id='x1-31294r145'></a><span class='ecrm-0500'>145</span><span class='ectt-0800'>module_exit(chardev_exit);</span>
|
|
<a id='x1-31296r146'></a><span class='ecrm-0500'>146</span>
|
|
<a id='x1-31298r147'></a><span class='ecrm-0500'>147</span><span class='ectt-0800'>MODULE_LICENSE(</span><span id='textcolor543'><span class='ectt-0800'>"GPL"</span></span><span class='ectt-0800'>);</span></pre>
|
|
|
|
|
|
|
|
<!-- l. 936 --><p class='noindent'>
|
|
</p>
|
|
<h4 class='subsectionHead' id='writing-modules-for-multiple-kernel-versions'><span class='titlemark'>6.6 </span> <a id='x1-320006.6'></a>Writing Modules for Multiple Kernel Versions</h4>
|
|
<!-- l. 938 --><p class='noindent'>The system calls, which are the major interface the kernel shows to the processes,
|
|
generally stay the same across versions. A new system call may be added, but
|
|
usually the old ones will behave exactly like they used to. This is necessary for
|
|
backward compatibility – a new kernel version is not supposed to break regular
|
|
processes. In most cases, the device files will also remain the same. On the other
|
|
hand, the internal interfaces within the kernel can and do change between
|
|
versions.
|
|
</p><!-- l. 943 --><p class='indent'> There are differences between different kernel versions, and if you want
|
|
to support multiple kernel versions, you will find yourself having to code
|
|
conditional compilation directives. The way to do this to compare the macro
|
|
<code> <span class='ectt-1000'>LINUX_VERSION_CODE</span>
|
|
</code> to the macro <code> <span class='ectt-1000'>KERNEL_VERSION</span>
|
|
</code>. In version <span class='obeylines-h'><span class='verb'><span class='ectt-1000'>a.b.c</span></span></span> of the kernel, the value of this macro would be <img alt='216a+ 28b+ c ' class='math' src='lkmpg-for-ht0x.svg' />.
|
|
</p><!-- l. 947 --><p class='noindent'>
|
|
</p>
|
|
<h3 class='sectionHead' id='the-proc-file-system'><span class='titlemark'>7 </span> <a id='x1-330007'></a>The /proc File System</h3>
|
|
<!-- l. 949 --><p class='noindent'>In Linux, there is an additional mechanism for the kernel and kernel modules to send
|
|
information to processes — the <span class='obeylines-h'><span class='verb'><span class='ectt-1000'>/proc</span></span></span> file system. Originally designed to allow easy
|
|
access to information about processes (hence the name), it is now used by every bit
|
|
of the kernel which has something interesting to report, such as <span class='obeylines-h'><span class='verb'><span class='ectt-1000'>/proc/modules</span></span></span>
|
|
which provides the list of modules and <span class='obeylines-h'><span class='verb'><span class='ectt-1000'>/proc/meminfo</span></span></span> which gathers memory usage
|
|
statistics.
|
|
</p><!-- l. 952 --><p class='indent'> The method to use the proc file system is very similar to the one used with device
|
|
drivers — a structure is created with all the information needed for the <span class='obeylines-h'><span class='verb'><span class='ectt-1000'>/proc</span></span></span> file,
|
|
including pointers to any handler functions (in our case there is only one, the
|
|
one called when somebody attempts to read from the <span class='obeylines-h'><span class='verb'><span class='ectt-1000'>/proc</span></span></span> file). Then,
|
|
<code> <span class='ectt-1000'>init_module</span>
|
|
</code> registers the structure with the kernel and
|
|
<code> <span class='ectt-1000'>cleanup_module</span>
|
|
</code> unregisters it.
|
|
</p><!-- l. 955 --><p class='indent'> Normal file systems are located on a disk, rather than just in memory (which is
|
|
where <span class='obeylines-h'><span class='verb'><span class='ectt-1000'>/proc</span></span></span> is), and in that case the inode number is a pointer to a disk
|
|
location where the file’s index-node (inode for short) is located. The inode
|
|
contains information about the file, for example the file’s permissions, together
|
|
with a pointer to the disk location or locations where the file’s data can be
|
|
found.
|
|
</p><!-- l. 958 --><p class='indent'> Because we don’t get called when the file is opened or closed, there’s nowhere for
|
|
us to put <code> <span class='ectt-1000'>try_module_get</span>
|
|
</code> and <code> <span class='ectt-1000'>module_put</span>
|
|
</code> in this module, and if the file is opened and then the module is removed, there’s no
|
|
|
|
|
|
|
|
way to avoid the consequences.
|
|
</p><!-- l. 960 --><p class='indent'> Here a simple example showing how to use a <span class='obeylines-h'><span class='verb'><span class='ectt-1000'>/proc</span></span></span> file. This is the HelloWorld for
|
|
the <span class='obeylines-h'><span class='verb'><span class='ectt-1000'>/proc</span></span></span> filesystem. There are three parts: create the file <span class='obeylines-h'><span class='verb'><span class='ectt-1000'>/proc/helloworld</span></span></span> in the
|
|
function <code> <span class='ectt-1000'>init_module</span>
|
|
</code>, return a value (and a buffer) when the file <span class='obeylines-h'><span class='verb'><span class='ectt-1000'>/proc/helloworld</span></span></span> is read in the callback
|
|
function <code> <span class='ectt-1000'>procfile_read</span>
|
|
</code>, and delete the file <span class='obeylines-h'><span class='verb'><span class='ectt-1000'>/proc/helloworld</span></span></span> in the function
|
|
<code> <span class='ectt-1000'>cleanup_module</span>
|
|
</code>.
|
|
</p><!-- l. 964 --><p class='indent'> The <span class='obeylines-h'><span class='verb'><span class='ectt-1000'>/proc/helloworld</span></span></span> is created when the module is loaded with the function
|
|
<code> <span class='ectt-1000'>proc_create</span>
|
|
</code>. The return value is a <code> <span id='textcolor544'><span class='ectt-1000'>struct</span></span><span class='ectt-1000'> proc_dir_entry</span>
|
|
</code>, and it will be used to configure the file <span class='obeylines-h'><span class='verb'><span class='ectt-1000'>/proc/helloworld</span></span></span> (for example, the owner
|
|
of this file). A null return value means that the creation has failed.
|
|
</p><!-- l. 968 --><p class='indent'> Every time the file <span class='obeylines-h'><span class='verb'><span class='ectt-1000'>/proc/helloworld</span></span></span> is read, the function
|
|
<code> <span class='ectt-1000'>procfile_read</span>
|
|
</code> is called. Two parameters of this function are very important: the buffer
|
|
(the second parameter) and the offset (the fourth one). The content of the
|
|
buffer will be returned to the application which read it (for example the
|
|
<code> <span class='ectt-1000'>cat</span>
|
|
</code> command). The offset is the current position in the file. If the return value of the
|
|
function is not null, then this function is called again. So be careful with this
|
|
function, if it never returns zero, the read function is called endlessly.
|
|
|
|
|
|
|
|
</p>
|
|
<pre class='verbatim' id='verbatim-10'>
|
|
$ cat /proc/helloworld
|
|
HelloWorld!
|
|
</pre>
|
|
<!-- l. 978 --><p class='nopar'>
|
|
</p><!-- l. 1 --><p class='indent'>
|
|
</p>
|
|
<pre class='fancyvrb' id='fancyvrb38'><a id='x1-33013r1'></a><span class='ecrm-0500'>1</span><span id='textcolor545'><span class='ectt-0800'>/*</span></span>
|
|
<a id='x1-33015r2'></a><span class='ecrm-0500'>2</span><span id='textcolor546'><span class='ectt-0800'> * procfs1.c</span></span>
|
|
<a id='x1-33017r3'></a><span class='ecrm-0500'>3</span><span id='textcolor547'><span class='ectt-0800'> */</span></span>
|
|
<a id='x1-33019r4'></a><span class='ecrm-0500'>4</span>
|
|
<a id='x1-33021r5'></a><span class='ecrm-0500'>5</span><span id='textcolor548'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor549'><span class='ectt-0800'><linux/kernel.h></span></span>
|
|
<a id='x1-33023r6'></a><span class='ecrm-0500'>6</span><span id='textcolor550'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor551'><span class='ectt-0800'><linux/module.h></span></span>
|
|
<a id='x1-33025r7'></a><span class='ecrm-0500'>7</span><span id='textcolor552'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor553'><span class='ectt-0800'><linux/proc_fs.h></span></span>
|
|
<a id='x1-33027r8'></a><span class='ecrm-0500'>8</span><span id='textcolor554'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor555'><span class='ectt-0800'><linux/uaccess.h></span></span>
|
|
<a id='x1-33029r9'></a><span class='ecrm-0500'>9</span><span id='textcolor556'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor557'><span class='ectt-0800'><linux/version.h></span></span>
|
|
<a id='x1-33031r10'></a><span class='ecrm-0500'>10</span>
|
|
<a id='x1-33033r11'></a><span class='ecrm-0500'>11</span><span id='textcolor558'><span class='ectt-0800'>#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 6, 0)</span></span>
|
|
<a id='x1-33035r12'></a><span class='ecrm-0500'>12</span><span id='textcolor559'><span class='ectt-0800'>#define HAVE_PROC_OPS</span></span>
|
|
<a id='x1-33037r13'></a><span class='ecrm-0500'>13</span><span id='textcolor560'><span class='ectt-0800'>#endif</span></span>
|
|
<a id='x1-33039r14'></a><span class='ecrm-0500'>14</span>
|
|
<a id='x1-33041r15'></a><span class='ecrm-0500'>15</span><span id='textcolor561'><span class='ectt-0800'>#define procfs_name "helloworld"</span></span>
|
|
<a id='x1-33043r16'></a><span class='ecrm-0500'>16</span>
|
|
<a id='x1-33045r17'></a><span class='ecrm-0500'>17</span><span id='textcolor562'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor563'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> proc_dir_entry *our_proc_file;</span>
|
|
<a id='x1-33047r18'></a><span class='ecrm-0500'>18</span>
|
|
<a id='x1-33049r19'></a><span class='ecrm-0500'>19</span><span id='textcolor564'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor565'><span class='ectt-0800'>ssize_t</span></span><span class='ectt-0800'> procfile_read(</span><span id='textcolor566'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> file *filePointer, </span><span id='textcolor567'><span class='ectt-0800'>char</span></span><span class='ectt-0800'> __user *buffer,</span>
|
|
<a id='x1-33051r20'></a><span class='ecrm-0500'>20</span><span class='ectt-0800'> </span><span id='textcolor568'><span class='ectt-0800'>size_t</span></span><span class='ectt-0800'> buffer_length, loff_t *offset)</span>
|
|
<a id='x1-33053r21'></a><span class='ecrm-0500'>21</span><span class='ectt-0800'>{</span>
|
|
<a id='x1-33055r22'></a><span class='ecrm-0500'>22</span><span class='ectt-0800'> </span><span id='textcolor569'><span class='ectt-0800'>char</span></span><span class='ectt-0800'> s[13] = </span><span id='textcolor570'><span class='ectt-0800'>"HelloWorld!</span></span><span id='textcolor571'><span class='ectt-0800'>\n</span></span><span id='textcolor572'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>;</span>
|
|
<a id='x1-33057r23'></a><span class='ecrm-0500'>23</span><span class='ectt-0800'> </span><span id='textcolor573'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> len = </span><span id='textcolor574'><span class='ectt-0800'>sizeof</span></span><span class='ectt-0800'>(s);</span>
|
|
<a id='x1-33059r24'></a><span class='ecrm-0500'>24</span><span class='ectt-0800'> </span><span id='textcolor575'><span class='ectt-0800'>ssize_t</span></span><span class='ectt-0800'> ret = len;</span>
|
|
<a id='x1-33061r25'></a><span class='ecrm-0500'>25</span>
|
|
<a id='x1-33063r26'></a><span class='ecrm-0500'>26</span><span class='ectt-0800'> </span><span id='textcolor576'><span class='ectt-0800'>if</span></span><span class='ectt-0800'> (*offset >= len || copy_to_user(buffer, s, len)) {</span>
|
|
<a id='x1-33065r27'></a><span class='ecrm-0500'>27</span><span class='ectt-0800'> pr_info(</span><span id='textcolor577'><span class='ectt-0800'>"copy_to_user failed</span></span><span id='textcolor578'><span class='ectt-0800'>\n</span></span><span id='textcolor579'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>);</span>
|
|
<a id='x1-33067r28'></a><span class='ecrm-0500'>28</span><span class='ectt-0800'> ret = 0;</span>
|
|
<a id='x1-33069r29'></a><span class='ecrm-0500'>29</span><span class='ectt-0800'> } </span><span id='textcolor580'><span class='ectt-0800'>else</span></span><span class='ectt-0800'> {</span>
|
|
<a id='x1-33071r30'></a><span class='ecrm-0500'>30</span><span class='ectt-0800'> pr_info(</span><span id='textcolor581'><span class='ectt-0800'>"procfile read %s</span></span><span id='textcolor582'><span class='ectt-0800'>\n</span></span><span id='textcolor583'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>, filePointer->f_path.dentry->d_name.name);</span>
|
|
<a id='x1-33073r31'></a><span class='ecrm-0500'>31</span><span class='ectt-0800'> *offset += len;</span>
|
|
<a id='x1-33075r32'></a><span class='ecrm-0500'>32</span><span class='ectt-0800'> }</span>
|
|
<a id='x1-33077r33'></a><span class='ecrm-0500'>33</span>
|
|
<a id='x1-33079r34'></a><span class='ecrm-0500'>34</span><span class='ectt-0800'> </span><span id='textcolor584'><span class='ectt-0800'>return</span></span><span class='ectt-0800'> ret;</span>
|
|
<a id='x1-33081r35'></a><span class='ecrm-0500'>35</span><span class='ectt-0800'>}</span>
|
|
<a id='x1-33083r36'></a><span class='ecrm-0500'>36</span>
|
|
<a id='x1-33085r37'></a><span class='ecrm-0500'>37</span><span id='textcolor585'><span class='ectt-0800'>#ifdef HAVE_PROC_OPS</span></span>
|
|
<a id='x1-33087r38'></a><span class='ecrm-0500'>38</span><span id='textcolor586'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor587'><span class='ectt-0800'>const</span></span><span class='ectt-0800'> </span><span id='textcolor588'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> proc_ops proc_file_fops = {</span>
|
|
<a id='x1-33089r39'></a><span class='ecrm-0500'>39</span><span class='ectt-0800'> .proc_read = procfile_read,</span>
|
|
<a id='x1-33091r40'></a><span class='ecrm-0500'>40</span><span class='ectt-0800'>};</span>
|
|
<a id='x1-33093r41'></a><span class='ecrm-0500'>41</span><span id='textcolor589'><span class='ectt-0800'>#else</span></span>
|
|
<a id='x1-33095r42'></a><span class='ecrm-0500'>42</span><span id='textcolor590'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor591'><span class='ectt-0800'>const</span></span><span class='ectt-0800'> </span><span id='textcolor592'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> file_operations proc_file_fops = {</span>
|
|
<a id='x1-33097r43'></a><span class='ecrm-0500'>43</span><span class='ectt-0800'> .read = procfile_read,</span>
|
|
<a id='x1-33099r44'></a><span class='ecrm-0500'>44</span><span class='ectt-0800'>};</span>
|
|
<a id='x1-33101r45'></a><span class='ecrm-0500'>45</span><span id='textcolor593'><span class='ectt-0800'>#endif</span></span>
|
|
<a id='x1-33103r46'></a><span class='ecrm-0500'>46</span>
|
|
<a id='x1-33105r47'></a><span class='ecrm-0500'>47</span><span id='textcolor594'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor595'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> __init procfs1_init(</span><span id='textcolor596'><span class='ectt-0800'>void</span></span><span class='ectt-0800'>)</span>
|
|
<a id='x1-33107r48'></a><span class='ecrm-0500'>48</span><span class='ectt-0800'>{</span>
|
|
<a id='x1-33109r49'></a><span class='ecrm-0500'>49</span><span class='ectt-0800'> our_proc_file = proc_create(procfs_name, 0644, NULL, &proc_file_fops);</span>
|
|
<a id='x1-33111r50'></a><span class='ecrm-0500'>50</span><span class='ectt-0800'> </span><span id='textcolor597'><span class='ectt-0800'>if</span></span><span class='ectt-0800'> (NULL == our_proc_file) {</span>
|
|
<a id='x1-33113r51'></a><span class='ecrm-0500'>51</span><span class='ectt-0800'> proc_remove(our_proc_file);</span>
|
|
<a id='x1-33115r52'></a><span class='ecrm-0500'>52</span><span class='ectt-0800'> pr_alert(</span><span id='textcolor598'><span class='ectt-0800'>"Error:Could not initialize /proc/%s</span></span><span id='textcolor599'><span class='ectt-0800'>\n</span></span><span id='textcolor600'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>, procfs_name);</span>
|
|
<a id='x1-33117r53'></a><span class='ecrm-0500'>53</span><span class='ectt-0800'> </span><span id='textcolor601'><span class='ectt-0800'>return</span></span><span class='ectt-0800'> -ENOMEM;</span>
|
|
<a id='x1-33119r54'></a><span class='ecrm-0500'>54</span><span class='ectt-0800'> }</span>
|
|
<a id='x1-33121r55'></a><span class='ecrm-0500'>55</span>
|
|
<a id='x1-33123r56'></a><span class='ecrm-0500'>56</span><span class='ectt-0800'> pr_info(</span><span id='textcolor602'><span class='ectt-0800'>"/proc/%s created</span></span><span id='textcolor603'><span class='ectt-0800'>\n</span></span><span id='textcolor604'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>, procfs_name);</span>
|
|
<a id='x1-33125r57'></a><span class='ecrm-0500'>57</span><span class='ectt-0800'> </span><span id='textcolor605'><span class='ectt-0800'>return</span></span><span class='ectt-0800'> 0;</span>
|
|
<a id='x1-33127r58'></a><span class='ecrm-0500'>58</span><span class='ectt-0800'>}</span>
|
|
<a id='x1-33129r59'></a><span class='ecrm-0500'>59</span>
|
|
<a id='x1-33131r60'></a><span class='ecrm-0500'>60</span><span id='textcolor606'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor607'><span class='ectt-0800'>void</span></span><span class='ectt-0800'> __exit procfs1_exit(</span><span id='textcolor608'><span class='ectt-0800'>void</span></span><span class='ectt-0800'>)</span>
|
|
<a id='x1-33133r61'></a><span class='ecrm-0500'>61</span><span class='ectt-0800'>{</span>
|
|
<a id='x1-33135r62'></a><span class='ecrm-0500'>62</span><span class='ectt-0800'> proc_remove(our_proc_file);</span>
|
|
<a id='x1-33137r63'></a><span class='ecrm-0500'>63</span><span class='ectt-0800'> pr_info(</span><span id='textcolor609'><span class='ectt-0800'>"/proc/%s removed</span></span><span id='textcolor610'><span class='ectt-0800'>\n</span></span><span id='textcolor611'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>, procfs_name);</span>
|
|
<a id='x1-33139r64'></a><span class='ecrm-0500'>64</span><span class='ectt-0800'>}</span>
|
|
<a id='x1-33141r65'></a><span class='ecrm-0500'>65</span>
|
|
<a id='x1-33143r66'></a><span class='ecrm-0500'>66</span><span class='ectt-0800'>module_init(procfs1_init);</span>
|
|
<a id='x1-33145r67'></a><span class='ecrm-0500'>67</span><span class='ectt-0800'>module_exit(procfs1_exit);</span>
|
|
<a id='x1-33147r68'></a><span class='ecrm-0500'>68</span>
|
|
<a id='x1-33149r69'></a><span class='ecrm-0500'>69</span><span class='ectt-0800'>MODULE_LICENSE(</span><span id='textcolor612'><span class='ectt-0800'>"GPL"</span></span><span class='ectt-0800'>);</span></pre>
|
|
<!-- l. 982 --><p class='noindent'>
|
|
</p>
|
|
<h4 class='subsectionHead' id='the-procops-structure'><span class='titlemark'>7.1 </span> <a id='x1-340007.1'></a>The proc_ops Structure</h4>
|
|
<!-- l. 984 --><p class='noindent'>The <code> <span class='ectt-1000'>proc_ops</span>
|
|
</code> structure is defined in <a href='https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/tree/include/linux/proc_fs.h'>include/linux/proc_fs.h</a> in Linux v5.6+. In older kernels, it
|
|
used <code> <span class='ectt-1000'>file_operations</span>
|
|
</code> for custom hooks in <span class='obeylines-h'><span class='verb'><span class='ectt-1000'>/proc</span></span></span> file system, but it contains some
|
|
members that are unnecessary in VFS, and every time VFS expands
|
|
<code> <span class='ectt-1000'>file_operations</span>
|
|
</code> set, <span class='obeylines-h'><span class='verb'><span class='ectt-1000'>/proc</span></span></span> code comes bloated. On the other hand, not only the space,
|
|
but also some operations were saved by this structure to improve its
|
|
performance. For example, the file which never disappears in <span class='obeylines-h'><span class='verb'><span class='ectt-1000'>/proc</span></span></span> can set the
|
|
<code> <span class='ectt-1000'>proc_flag</span>
|
|
</code> as <code> <span class='ectt-1000'>PROC_ENTRY_PERMANENT</span>
|
|
</code> to save 2 atomic ops, 1 allocation, 1 free in per open/read/close sequence.
|
|
</p><!-- l. 989 --><p class='noindent'>
|
|
</p>
|
|
<h4 class='subsectionHead' id='read-and-write-a-proc-file'><span class='titlemark'>7.2 </span> <a id='x1-350007.2'></a>Read and Write a /proc File</h4>
|
|
<!-- l. 991 --><p class='noindent'>We have seen a very simple example for a <span class='obeylines-h'><span class='verb'><span class='ectt-1000'>/proc</span></span></span> file where we only read
|
|
the file <span class='obeylines-h'><span class='verb'><span class='ectt-1000'>/proc/helloworld</span></span></span>. It is also possible to write in a <span class='obeylines-h'><span class='verb'><span class='ectt-1000'>/proc</span></span></span> file. It
|
|
works the same way as read, a function is called when the <span class='obeylines-h'><span class='verb'><span class='ectt-1000'>/proc</span></span></span> file
|
|
is written. But there is a little difference with read, data comes from
|
|
user, so you have to import data from user space to kernel space (with
|
|
<code> <span class='ectt-1000'>copy_from_user</span>
|
|
</code> or <code> <span class='ectt-1000'>get_user</span>
|
|
</code>)
|
|
</p><!-- l. 996 --><p class='indent'> The reason for <code> <span class='ectt-1000'>copy_from_user</span>
|
|
</code> or <code> <span class='ectt-1000'>get_user</span>
|
|
</code> is that Linux memory (on Intel architecture, it may be different under some
|
|
|
|
|
|
|
|
other processors) is segmented. This means that a pointer, by itself, does
|
|
not reference a unique location in memory, only a location in a memory
|
|
segment, and you need to know which memory segment it is to be able to use
|
|
it. There is one memory segment for the kernel, and one for each of the
|
|
processes.
|
|
</p><!-- l. 1000 --><p class='indent'> The only memory segment accessible to a process is its own, so when
|
|
writing regular programs to run as processes, there is no need to worry about
|
|
segments. When you write a kernel module, normally you want to access
|
|
the kernel memory segment, which is handled automatically by the system.
|
|
However, when the content of a memory buffer needs to be passed between
|
|
the currently running process and the kernel, the kernel function receives
|
|
a pointer to the memory buffer which is in the process segment. The
|
|
<code> <span class='ectt-1000'>put_user</span>
|
|
</code> and <code> <span class='ectt-1000'>get_user</span>
|
|
</code> macros allow you to access that memory. These functions handle
|
|
only one character, you can handle several characters with
|
|
<code> <span class='ectt-1000'>copy_to_user</span>
|
|
</code> and <code> <span class='ectt-1000'>copy_from_user</span>
|
|
</code>. As the buffer (in read or write function) is in kernel space, for write function you
|
|
need to import data because it comes from user space, but not for the read function
|
|
because data is already in kernel space.
|
|
</p><!-- l. 1 --><p class='indent'>
|
|
</p>
|
|
<pre class='fancyvrb' id='fancyvrb39'><a id='x1-35010r1'></a><span class='ecrm-0500'>1</span><span id='textcolor613'><span class='ectt-0800'>/*</span></span>
|
|
<a id='x1-35012r2'></a><span class='ecrm-0500'>2</span><span id='textcolor614'><span class='ectt-0800'> * procfs2.c - create a "file" in /proc</span></span>
|
|
<a id='x1-35014r3'></a><span class='ecrm-0500'>3</span><span id='textcolor615'><span class='ectt-0800'> */</span></span>
|
|
<a id='x1-35016r4'></a><span class='ecrm-0500'>4</span>
|
|
<a id='x1-35018r5'></a><span class='ecrm-0500'>5</span><span id='textcolor616'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor617'><span class='ectt-0800'><linux/kernel.h> /* We</span><span class='tctt-0800'>'</span><span class='ectt-0800'>re doing kernel work */</span></span>
|
|
<a id='x1-35020r6'></a><span class='ecrm-0500'>6</span><span id='textcolor618'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor619'><span class='ectt-0800'><linux/module.h> /* Specifically, a module */</span></span>
|
|
<a id='x1-35022r7'></a><span class='ecrm-0500'>7</span><span id='textcolor620'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor621'><span class='ectt-0800'><linux/proc_fs.h> /* Necessary because we use the proc fs */</span></span>
|
|
<a id='x1-35024r8'></a><span class='ecrm-0500'>8</span><span id='textcolor622'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor623'><span class='ectt-0800'><linux/uaccess.h> /* for copy_from_user */</span></span>
|
|
<a id='x1-35026r9'></a><span class='ecrm-0500'>9</span><span id='textcolor624'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor625'><span class='ectt-0800'><linux/version.h></span></span>
|
|
<a id='x1-35028r10'></a><span class='ecrm-0500'>10</span>
|
|
<a id='x1-35030r11'></a><span class='ecrm-0500'>11</span><span id='textcolor626'><span class='ectt-0800'>#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 6, 0)</span></span>
|
|
<a id='x1-35032r12'></a><span class='ecrm-0500'>12</span><span id='textcolor627'><span class='ectt-0800'>#define HAVE_PROC_OPS</span></span>
|
|
<a id='x1-35034r13'></a><span class='ecrm-0500'>13</span><span id='textcolor628'><span class='ectt-0800'>#endif</span></span>
|
|
<a id='x1-35036r14'></a><span class='ecrm-0500'>14</span>
|
|
<a id='x1-35038r15'></a><span class='ecrm-0500'>15</span><span id='textcolor629'><span class='ectt-0800'>#define PROCFS_MAX_SIZE 1024</span></span>
|
|
<a id='x1-35040r16'></a><span class='ecrm-0500'>16</span><span id='textcolor630'><span class='ectt-0800'>#define PROCFS_NAME "buffer1k"</span></span>
|
|
<a id='x1-35042r17'></a><span class='ecrm-0500'>17</span>
|
|
<a id='x1-35044r18'></a><span class='ecrm-0500'>18</span><span id='textcolor631'><span class='ectt-0800'>/* This structure hold information about the /proc file */</span></span>
|
|
<a id='x1-35046r19'></a><span class='ecrm-0500'>19</span><span id='textcolor632'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor633'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> proc_dir_entry *our_proc_file;</span>
|
|
<a id='x1-35048r20'></a><span class='ecrm-0500'>20</span>
|
|
<a id='x1-35050r21'></a><span class='ecrm-0500'>21</span><span id='textcolor634'><span class='ectt-0800'>/* The buffer used to store character for this module */</span></span>
|
|
<a id='x1-35052r22'></a><span class='ecrm-0500'>22</span><span id='textcolor635'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor636'><span class='ectt-0800'>char</span></span><span class='ectt-0800'> procfs_buffer[PROCFS_MAX_SIZE];</span>
|
|
<a id='x1-35054r23'></a><span class='ecrm-0500'>23</span>
|
|
<a id='x1-35056r24'></a><span class='ecrm-0500'>24</span><span id='textcolor637'><span class='ectt-0800'>/* The size of the buffer */</span></span>
|
|
<a id='x1-35058r25'></a><span class='ecrm-0500'>25</span><span id='textcolor638'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor639'><span class='ectt-0800'>unsigned</span></span><span class='ectt-0800'> </span><span id='textcolor640'><span class='ectt-0800'>long</span></span><span class='ectt-0800'> procfs_buffer_size = 0;</span>
|
|
<a id='x1-35060r26'></a><span class='ecrm-0500'>26</span>
|
|
<a id='x1-35062r27'></a><span class='ecrm-0500'>27</span><span id='textcolor641'><span class='ectt-0800'>/* This function is called then the /proc file is read */</span></span>
|
|
<a id='x1-35064r28'></a><span class='ecrm-0500'>28</span><span id='textcolor642'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor643'><span class='ectt-0800'>ssize_t</span></span><span class='ectt-0800'> procfile_read(</span><span id='textcolor644'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> file *filePointer, </span><span id='textcolor645'><span class='ectt-0800'>char</span></span><span class='ectt-0800'> __user *buffer,</span>
|
|
<a id='x1-35066r29'></a><span class='ecrm-0500'>29</span><span class='ectt-0800'> </span><span id='textcolor646'><span class='ectt-0800'>size_t</span></span><span class='ectt-0800'> buffer_length, loff_t *offset)</span>
|
|
<a id='x1-35068r30'></a><span class='ecrm-0500'>30</span><span class='ectt-0800'>{</span>
|
|
<a id='x1-35070r31'></a><span class='ecrm-0500'>31</span><span class='ectt-0800'> </span><span id='textcolor647'><span class='ectt-0800'>char</span></span><span class='ectt-0800'> s[13] = </span><span id='textcolor648'><span class='ectt-0800'>"HelloWorld!</span></span><span id='textcolor649'><span class='ectt-0800'>\n</span></span><span id='textcolor650'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>;</span>
|
|
<a id='x1-35072r32'></a><span class='ecrm-0500'>32</span><span class='ectt-0800'> </span><span id='textcolor651'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> len = </span><span id='textcolor652'><span class='ectt-0800'>sizeof</span></span><span class='ectt-0800'>(s);</span>
|
|
<a id='x1-35074r33'></a><span class='ecrm-0500'>33</span><span class='ectt-0800'> </span><span id='textcolor653'><span class='ectt-0800'>ssize_t</span></span><span class='ectt-0800'> ret = len;</span>
|
|
<a id='x1-35076r34'></a><span class='ecrm-0500'>34</span>
|
|
<a id='x1-35078r35'></a><span class='ecrm-0500'>35</span><span class='ectt-0800'> </span><span id='textcolor654'><span class='ectt-0800'>if</span></span><span class='ectt-0800'> (*offset >= len || copy_to_user(buffer, s, len)) {</span>
|
|
<a id='x1-35080r36'></a><span class='ecrm-0500'>36</span><span class='ectt-0800'> pr_info(</span><span id='textcolor655'><span class='ectt-0800'>"copy_to_user failed</span></span><span id='textcolor656'><span class='ectt-0800'>\n</span></span><span id='textcolor657'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>);</span>
|
|
<a id='x1-35082r37'></a><span class='ecrm-0500'>37</span><span class='ectt-0800'> ret = 0;</span>
|
|
<a id='x1-35084r38'></a><span class='ecrm-0500'>38</span><span class='ectt-0800'> } </span><span id='textcolor658'><span class='ectt-0800'>else</span></span><span class='ectt-0800'> {</span>
|
|
<a id='x1-35086r39'></a><span class='ecrm-0500'>39</span><span class='ectt-0800'> pr_info(</span><span id='textcolor659'><span class='ectt-0800'>"procfile read %s</span></span><span id='textcolor660'><span class='ectt-0800'>\n</span></span><span id='textcolor661'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>, filePointer->f_path.dentry->d_name.name);</span>
|
|
<a id='x1-35088r40'></a><span class='ecrm-0500'>40</span><span class='ectt-0800'> *offset += len;</span>
|
|
<a id='x1-35090r41'></a><span class='ecrm-0500'>41</span><span class='ectt-0800'> }</span>
|
|
<a id='x1-35092r42'></a><span class='ecrm-0500'>42</span>
|
|
<a id='x1-35094r43'></a><span class='ecrm-0500'>43</span><span class='ectt-0800'> </span><span id='textcolor662'><span class='ectt-0800'>return</span></span><span class='ectt-0800'> ret;</span>
|
|
<a id='x1-35096r44'></a><span class='ecrm-0500'>44</span><span class='ectt-0800'>}</span>
|
|
<a id='x1-35098r45'></a><span class='ecrm-0500'>45</span>
|
|
<a id='x1-35100r46'></a><span class='ecrm-0500'>46</span><span id='textcolor663'><span class='ectt-0800'>/* This function is called with the /proc file is written. */</span></span>
|
|
<a id='x1-35102r47'></a><span class='ecrm-0500'>47</span><span id='textcolor664'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor665'><span class='ectt-0800'>ssize_t</span></span><span class='ectt-0800'> procfile_write(</span><span id='textcolor666'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> file *file, </span><span id='textcolor667'><span class='ectt-0800'>const</span></span><span class='ectt-0800'> </span><span id='textcolor668'><span class='ectt-0800'>char</span></span><span class='ectt-0800'> __user *buff,</span>
|
|
<a id='x1-35104r48'></a><span class='ecrm-0500'>48</span><span class='ectt-0800'> </span><span id='textcolor669'><span class='ectt-0800'>size_t</span></span><span class='ectt-0800'> len, loff_t *off)</span>
|
|
<a id='x1-35106r49'></a><span class='ecrm-0500'>49</span><span class='ectt-0800'>{</span>
|
|
<a id='x1-35108r50'></a><span class='ecrm-0500'>50</span><span class='ectt-0800'> procfs_buffer_size = len;</span>
|
|
<a id='x1-35110r51'></a><span class='ecrm-0500'>51</span><span class='ectt-0800'> </span><span id='textcolor670'><span class='ectt-0800'>if</span></span><span class='ectt-0800'> (procfs_buffer_size > PROCFS_MAX_SIZE)</span>
|
|
<a id='x1-35112r52'></a><span class='ecrm-0500'>52</span><span class='ectt-0800'> procfs_buffer_size = PROCFS_MAX_SIZE;</span>
|
|
<a id='x1-35114r53'></a><span class='ecrm-0500'>53</span>
|
|
<a id='x1-35116r54'></a><span class='ecrm-0500'>54</span><span class='ectt-0800'> </span><span id='textcolor671'><span class='ectt-0800'>if</span></span><span class='ectt-0800'> (copy_from_user(procfs_buffer, buff, procfs_buffer_size))</span>
|
|
<a id='x1-35118r55'></a><span class='ecrm-0500'>55</span><span class='ectt-0800'> </span><span id='textcolor672'><span class='ectt-0800'>return</span></span><span class='ectt-0800'> -EFAULT;</span>
|
|
<a id='x1-35120r56'></a><span class='ecrm-0500'>56</span>
|
|
<a id='x1-35122r57'></a><span class='ecrm-0500'>57</span><span class='ectt-0800'> procfs_buffer[procfs_buffer_size] = </span><span id='textcolor673'><span class='tctt-0800'>'</span><span class='ectt-0800'>\0</span><span class='tctt-0800'>'</span></span><span class='ectt-0800'>;</span>
|
|
<a id='x1-35124r58'></a><span class='ecrm-0500'>58</span><span class='ectt-0800'> </span><span id='textcolor674'><span class='ectt-0800'>return</span></span><span class='ectt-0800'> procfs_buffer_size;</span>
|
|
<a id='x1-35126r59'></a><span class='ecrm-0500'>59</span><span class='ectt-0800'>}</span>
|
|
<a id='x1-35128r60'></a><span class='ecrm-0500'>60</span>
|
|
<a id='x1-35130r61'></a><span class='ecrm-0500'>61</span><span id='textcolor675'><span class='ectt-0800'>#ifdef HAVE_PROC_OPS</span></span>
|
|
<a id='x1-35132r62'></a><span class='ecrm-0500'>62</span><span id='textcolor676'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor677'><span class='ectt-0800'>const</span></span><span class='ectt-0800'> </span><span id='textcolor678'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> proc_ops proc_file_fops = {</span>
|
|
<a id='x1-35134r63'></a><span class='ecrm-0500'>63</span><span class='ectt-0800'> .proc_read = procfile_read,</span>
|
|
<a id='x1-35136r64'></a><span class='ecrm-0500'>64</span><span class='ectt-0800'> .proc_write = procfile_write,</span>
|
|
<a id='x1-35138r65'></a><span class='ecrm-0500'>65</span><span class='ectt-0800'>};</span>
|
|
<a id='x1-35140r66'></a><span class='ecrm-0500'>66</span><span id='textcolor679'><span class='ectt-0800'>#else</span></span>
|
|
<a id='x1-35142r67'></a><span class='ecrm-0500'>67</span><span id='textcolor680'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor681'><span class='ectt-0800'>const</span></span><span class='ectt-0800'> </span><span id='textcolor682'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> file_operations proc_file_fops = {</span>
|
|
<a id='x1-35144r68'></a><span class='ecrm-0500'>68</span><span class='ectt-0800'> .read = procfile_read,</span>
|
|
<a id='x1-35146r69'></a><span class='ecrm-0500'>69</span><span class='ectt-0800'> .write = procfile_write,</span>
|
|
<a id='x1-35148r70'></a><span class='ecrm-0500'>70</span><span class='ectt-0800'>};</span>
|
|
<a id='x1-35150r71'></a><span class='ecrm-0500'>71</span><span id='textcolor683'><span class='ectt-0800'>#endif</span></span>
|
|
<a id='x1-35152r72'></a><span class='ecrm-0500'>72</span>
|
|
<a id='x1-35154r73'></a><span class='ecrm-0500'>73</span><span id='textcolor684'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor685'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> __init procfs2_init(</span><span id='textcolor686'><span class='ectt-0800'>void</span></span><span class='ectt-0800'>)</span>
|
|
<a id='x1-35156r74'></a><span class='ecrm-0500'>74</span><span class='ectt-0800'>{</span>
|
|
<a id='x1-35158r75'></a><span class='ecrm-0500'>75</span><span class='ectt-0800'> our_proc_file = proc_create(PROCFS_NAME, 0644, NULL, &proc_file_fops);</span>
|
|
<a id='x1-35160r76'></a><span class='ecrm-0500'>76</span><span class='ectt-0800'> </span><span id='textcolor687'><span class='ectt-0800'>if</span></span><span class='ectt-0800'> (NULL == our_proc_file) {</span>
|
|
<a id='x1-35162r77'></a><span class='ecrm-0500'>77</span><span class='ectt-0800'> proc_remove(our_proc_file);</span>
|
|
<a id='x1-35164r78'></a><span class='ecrm-0500'>78</span><span class='ectt-0800'> pr_alert(</span><span id='textcolor688'><span class='ectt-0800'>"Error:Could not initialize /proc/%s</span></span><span id='textcolor689'><span class='ectt-0800'>\n</span></span><span id='textcolor690'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>, PROCFS_NAME);</span>
|
|
<a id='x1-35166r79'></a><span class='ecrm-0500'>79</span><span class='ectt-0800'> </span><span id='textcolor691'><span class='ectt-0800'>return</span></span><span class='ectt-0800'> -ENOMEM;</span>
|
|
<a id='x1-35168r80'></a><span class='ecrm-0500'>80</span><span class='ectt-0800'> }</span>
|
|
<a id='x1-35170r81'></a><span class='ecrm-0500'>81</span>
|
|
<a id='x1-35172r82'></a><span class='ecrm-0500'>82</span><span class='ectt-0800'> pr_info(</span><span id='textcolor692'><span class='ectt-0800'>"/proc/%s created</span></span><span id='textcolor693'><span class='ectt-0800'>\n</span></span><span id='textcolor694'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>, PROCFS_NAME);</span>
|
|
<a id='x1-35174r83'></a><span class='ecrm-0500'>83</span><span class='ectt-0800'> </span><span id='textcolor695'><span class='ectt-0800'>return</span></span><span class='ectt-0800'> 0;</span>
|
|
<a id='x1-35176r84'></a><span class='ecrm-0500'>84</span><span class='ectt-0800'>}</span>
|
|
<a id='x1-35178r85'></a><span class='ecrm-0500'>85</span>
|
|
<a id='x1-35180r86'></a><span class='ecrm-0500'>86</span><span id='textcolor696'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor697'><span class='ectt-0800'>void</span></span><span class='ectt-0800'> __exit procfs2_exit(</span><span id='textcolor698'><span class='ectt-0800'>void</span></span><span class='ectt-0800'>)</span>
|
|
<a id='x1-35182r87'></a><span class='ecrm-0500'>87</span><span class='ectt-0800'>{</span>
|
|
<a id='x1-35184r88'></a><span class='ecrm-0500'>88</span><span class='ectt-0800'> proc_remove(our_proc_file);</span>
|
|
<a id='x1-35186r89'></a><span class='ecrm-0500'>89</span><span class='ectt-0800'> pr_info(</span><span id='textcolor699'><span class='ectt-0800'>"/proc/%s removed</span></span><span id='textcolor700'><span class='ectt-0800'>\n</span></span><span id='textcolor701'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>, PROCFS_NAME);</span>
|
|
<a id='x1-35188r90'></a><span class='ecrm-0500'>90</span><span class='ectt-0800'>}</span>
|
|
<a id='x1-35190r91'></a><span class='ecrm-0500'>91</span>
|
|
<a id='x1-35192r92'></a><span class='ecrm-0500'>92</span><span class='ectt-0800'>module_init(procfs2_init);</span>
|
|
<a id='x1-35194r93'></a><span class='ecrm-0500'>93</span><span class='ectt-0800'>module_exit(procfs2_exit);</span>
|
|
<a id='x1-35196r94'></a><span class='ecrm-0500'>94</span>
|
|
<a id='x1-35198r95'></a><span class='ecrm-0500'>95</span><span class='ectt-0800'>MODULE_LICENSE(</span><span id='textcolor702'><span class='ectt-0800'>"GPL"</span></span><span class='ectt-0800'>);</span></pre>
|
|
<!-- l. 1009 --><p class='noindent'>
|
|
</p>
|
|
<h4 class='subsectionHead' id='manage-proc-file-with-standard-filesystem'><span class='titlemark'>7.3 </span> <a id='x1-360007.3'></a>Manage /proc file with standard filesystem</h4>
|
|
<!-- l. 1011 --><p class='noindent'>We have seen how to read and write a <span class='obeylines-h'><span class='verb'><span class='ectt-1000'>/proc</span></span></span> file with the <span class='obeylines-h'><span class='verb'><span class='ectt-1000'>/proc</span></span></span> interface. But it is
|
|
also possible to manage <span class='obeylines-h'><span class='verb'><span class='ectt-1000'>/proc</span></span></span> file with inodes. The main concern is to use advanced
|
|
functions, like permissions.
|
|
</p><!-- l. 1015 --><p class='indent'> In Linux, there is a standard mechanism for file system registration.
|
|
Since every file system has to have its own functions to handle inode and file
|
|
operations, there is a special structure to hold pointers to all those functions,
|
|
<code> <span id='textcolor703'><span class='ectt-1000'>struct</span></span><span class='ectt-1000'> inode_operations</span>
|
|
</code>, which includes a pointer to <code> <span id='textcolor704'><span class='ectt-1000'>struct</span></span><span class='ectt-1000'> proc_ops</span>
|
|
</code>.
|
|
</p><!-- l. 1018 --><p class='indent'> The difference between file and inode operations is that file operations deal with
|
|
the file itself whereas inode operations deal with ways of referencing the file, such as
|
|
creating links to it.
|
|
</p><!-- l. 1020 --><p class='indent'> In <span class='obeylines-h'><span class='verb'><span class='ectt-1000'>/proc</span></span></span>, whenever we register a new file, we’re allowed to specify which
|
|
<code> <span id='textcolor705'><span class='ectt-1000'>struct</span></span><span class='ectt-1000'> inode_operations</span>
|
|
</code> will be used to access to it. This is the mechanism we use, a
|
|
<code> <span id='textcolor706'><span class='ectt-1000'>struct</span></span><span class='ectt-1000'> inode_operations</span>
|
|
|
|
|
|
|
|
</code> which includes a pointer to a <code> <span id='textcolor707'><span class='ectt-1000'>struct</span></span><span class='ectt-1000'> proc_ops</span>
|
|
</code> which includes pointers to our <code> <span class='ectt-1000'>procf_read</span>
|
|
</code> and <code> <span class='ectt-1000'>procfs_write</span>
|
|
</code> functions.
|
|
</p><!-- l. 1023 --><p class='indent'> Another interesting point here is the
|
|
<code> <span class='ectt-1000'>module_permission</span>
|
|
</code> function. This function is called whenever a process tries to do something with the
|
|
<span class='obeylines-h'><span class='verb'><span class='ectt-1000'>/proc</span></span></span> file, and it can decide whether to allow access or not. Right now it is only
|
|
based on the operation and the uid of the current user (as available in current, a
|
|
pointer to a structure which includes information on the currently running
|
|
process), but it could be based on anything we like, such as what other
|
|
processes are doing with the same file, the time of day, or the last input we
|
|
received.
|
|
</p><!-- l. 1027 --><p class='indent'> It is important to note that the standard roles of read and write are reversed in
|
|
the kernel. Read functions are used for output, whereas write functions are used for
|
|
input. The reason for that is that read and write refer to the user’s point of view — if
|
|
a process reads something from the kernel, then the kernel needs to output it, and
|
|
if a process writes something to the kernel, then the kernel receives it as
|
|
input.
|
|
</p><!-- l. 1 --><p class='indent'>
|
|
</p>
|
|
<pre class='fancyvrb' id='fancyvrb40'><a id='x1-36010r1'></a><span class='ecrm-0500'>1</span><span id='textcolor708'><span class='ectt-0800'>/*</span></span>
|
|
<a id='x1-36012r2'></a><span class='ecrm-0500'>2</span><span id='textcolor709'><span class='ectt-0800'> * procfs3.c</span></span>
|
|
<a id='x1-36014r3'></a><span class='ecrm-0500'>3</span><span id='textcolor710'><span class='ectt-0800'> */</span></span>
|
|
<a id='x1-36016r4'></a><span class='ecrm-0500'>4</span>
|
|
<a id='x1-36018r5'></a><span class='ecrm-0500'>5</span><span id='textcolor711'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor712'><span class='ectt-0800'><linux/kernel.h></span></span>
|
|
<a id='x1-36020r6'></a><span class='ecrm-0500'>6</span><span id='textcolor713'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor714'><span class='ectt-0800'><linux/module.h></span></span>
|
|
<a id='x1-36022r7'></a><span class='ecrm-0500'>7</span><span id='textcolor715'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor716'><span class='ectt-0800'><linux/proc_fs.h></span></span>
|
|
<a id='x1-36024r8'></a><span class='ecrm-0500'>8</span><span id='textcolor717'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor718'><span class='ectt-0800'><linux/sched.h></span></span>
|
|
<a id='x1-36026r9'></a><span class='ecrm-0500'>9</span><span id='textcolor719'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor720'><span class='ectt-0800'><linux/uaccess.h></span></span>
|
|
<a id='x1-36028r10'></a><span class='ecrm-0500'>10</span><span id='textcolor721'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor722'><span class='ectt-0800'><linux/version.h></span></span>
|
|
<a id='x1-36030r11'></a><span class='ecrm-0500'>11</span>
|
|
<a id='x1-36032r12'></a><span class='ecrm-0500'>12</span><span id='textcolor723'><span class='ectt-0800'>#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 6, 0)</span></span>
|
|
<a id='x1-36034r13'></a><span class='ecrm-0500'>13</span><span id='textcolor724'><span class='ectt-0800'>#define HAVE_PROC_OPS</span></span>
|
|
<a id='x1-36036r14'></a><span class='ecrm-0500'>14</span><span id='textcolor725'><span class='ectt-0800'>#endif</span></span>
|
|
<a id='x1-36038r15'></a><span class='ecrm-0500'>15</span>
|
|
<a id='x1-36040r16'></a><span class='ecrm-0500'>16</span><span id='textcolor726'><span class='ectt-0800'>#define PROCFS_MAX_SIZE 2048</span></span>
|
|
<a id='x1-36042r17'></a><span class='ecrm-0500'>17</span><span id='textcolor727'><span class='ectt-0800'>#define PROCFS_ENTRY_FILENAME "buffer2k"</span></span>
|
|
<a id='x1-36044r18'></a><span class='ecrm-0500'>18</span>
|
|
<a id='x1-36046r19'></a><span class='ecrm-0500'>19</span><span id='textcolor728'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor729'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> proc_dir_entry *our_proc_file;</span>
|
|
<a id='x1-36048r20'></a><span class='ecrm-0500'>20</span><span id='textcolor730'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor731'><span class='ectt-0800'>char</span></span><span class='ectt-0800'> procfs_buffer[PROCFS_MAX_SIZE];</span>
|
|
<a id='x1-36050r21'></a><span class='ecrm-0500'>21</span><span id='textcolor732'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor733'><span class='ectt-0800'>unsigned</span></span><span class='ectt-0800'> </span><span id='textcolor734'><span class='ectt-0800'>long</span></span><span class='ectt-0800'> procfs_buffer_size = 0;</span>
|
|
<a id='x1-36052r22'></a><span class='ecrm-0500'>22</span>
|
|
<a id='x1-36054r23'></a><span class='ecrm-0500'>23</span><span id='textcolor735'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor736'><span class='ectt-0800'>ssize_t</span></span><span class='ectt-0800'> procfs_read(</span><span id='textcolor737'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> file *filp, </span><span id='textcolor738'><span class='ectt-0800'>char</span></span><span class='ectt-0800'> __user *buffer,</span>
|
|
<a id='x1-36056r24'></a><span class='ecrm-0500'>24</span><span class='ectt-0800'> </span><span id='textcolor739'><span class='ectt-0800'>size_t</span></span><span class='ectt-0800'> length, loff_t *offset)</span>
|
|
<a id='x1-36058r25'></a><span class='ecrm-0500'>25</span><span class='ectt-0800'>{</span>
|
|
<a id='x1-36060r26'></a><span class='ecrm-0500'>26</span><span class='ectt-0800'> </span><span id='textcolor740'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor741'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> finished = 0;</span>
|
|
<a id='x1-36062r27'></a><span class='ecrm-0500'>27</span>
|
|
<a id='x1-36064r28'></a><span class='ecrm-0500'>28</span><span class='ectt-0800'> </span><span id='textcolor742'><span class='ectt-0800'>if</span></span><span class='ectt-0800'> (finished) {</span>
|
|
<a id='x1-36066r29'></a><span class='ecrm-0500'>29</span><span class='ectt-0800'> pr_debug(</span><span id='textcolor743'><span class='ectt-0800'>"procfs_read: END</span></span><span id='textcolor744'><span class='ectt-0800'>\n</span></span><span id='textcolor745'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>);</span>
|
|
<a id='x1-36068r30'></a><span class='ecrm-0500'>30</span><span class='ectt-0800'> finished = 0;</span>
|
|
<a id='x1-36070r31'></a><span class='ecrm-0500'>31</span><span class='ectt-0800'> </span><span id='textcolor746'><span class='ectt-0800'>return</span></span><span class='ectt-0800'> 0;</span>
|
|
<a id='x1-36072r32'></a><span class='ecrm-0500'>32</span><span class='ectt-0800'> }</span>
|
|
<a id='x1-36074r33'></a><span class='ecrm-0500'>33</span><span class='ectt-0800'> finished = 1;</span>
|
|
<a id='x1-36076r34'></a><span class='ecrm-0500'>34</span>
|
|
<a id='x1-36078r35'></a><span class='ecrm-0500'>35</span><span class='ectt-0800'> </span><span id='textcolor747'><span class='ectt-0800'>if</span></span><span class='ectt-0800'> (copy_to_user(buffer, procfs_buffer, procfs_buffer_size))</span>
|
|
<a id='x1-36080r36'></a><span class='ecrm-0500'>36</span><span class='ectt-0800'> </span><span id='textcolor748'><span class='ectt-0800'>return</span></span><span class='ectt-0800'> -EFAULT;</span>
|
|
<a id='x1-36082r37'></a><span class='ecrm-0500'>37</span>
|
|
<a id='x1-36084r38'></a><span class='ecrm-0500'>38</span><span class='ectt-0800'> pr_debug(</span><span id='textcolor749'><span class='ectt-0800'>"procfs_read: read %lu bytes</span></span><span id='textcolor750'><span class='ectt-0800'>\n</span></span><span id='textcolor751'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>, procfs_buffer_size);</span>
|
|
<a id='x1-36086r39'></a><span class='ecrm-0500'>39</span><span class='ectt-0800'> </span><span id='textcolor752'><span class='ectt-0800'>return</span></span><span class='ectt-0800'> procfs_buffer_size;</span>
|
|
<a id='x1-36088r40'></a><span class='ecrm-0500'>40</span><span class='ectt-0800'>}</span>
|
|
<a id='x1-36090r41'></a><span class='ecrm-0500'>41</span><span id='textcolor753'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor754'><span class='ectt-0800'>ssize_t</span></span><span class='ectt-0800'> procfs_write(</span><span id='textcolor755'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> file *file, </span><span id='textcolor756'><span class='ectt-0800'>const</span></span><span class='ectt-0800'> </span><span id='textcolor757'><span class='ectt-0800'>char</span></span><span class='ectt-0800'> __user *buffer,</span>
|
|
<a id='x1-36092r42'></a><span class='ecrm-0500'>42</span><span class='ectt-0800'> </span><span id='textcolor758'><span class='ectt-0800'>size_t</span></span><span class='ectt-0800'> len, loff_t *off)</span>
|
|
<a id='x1-36094r43'></a><span class='ecrm-0500'>43</span><span class='ectt-0800'>{</span>
|
|
<a id='x1-36096r44'></a><span class='ecrm-0500'>44</span><span class='ectt-0800'> </span><span id='textcolor759'><span class='ectt-0800'>if</span></span><span class='ectt-0800'> (len > PROCFS_MAX_SIZE)</span>
|
|
<a id='x1-36098r45'></a><span class='ecrm-0500'>45</span><span class='ectt-0800'> procfs_buffer_size = PROCFS_MAX_SIZE;</span>
|
|
<a id='x1-36100r46'></a><span class='ecrm-0500'>46</span><span class='ectt-0800'> </span><span id='textcolor760'><span class='ectt-0800'>else</span></span>
|
|
<a id='x1-36102r47'></a><span class='ecrm-0500'>47</span><span class='ectt-0800'> procfs_buffer_size = len;</span>
|
|
<a id='x1-36104r48'></a><span class='ecrm-0500'>48</span><span class='ectt-0800'> </span><span id='textcolor761'><span class='ectt-0800'>if</span></span><span class='ectt-0800'> (copy_from_user(procfs_buffer, buffer, procfs_buffer_size))</span>
|
|
<a id='x1-36106r49'></a><span class='ecrm-0500'>49</span><span class='ectt-0800'> </span><span id='textcolor762'><span class='ectt-0800'>return</span></span><span class='ectt-0800'> -EFAULT;</span>
|
|
<a id='x1-36108r50'></a><span class='ecrm-0500'>50</span>
|
|
<a id='x1-36110r51'></a><span class='ecrm-0500'>51</span><span class='ectt-0800'> pr_debug(</span><span id='textcolor763'><span class='ectt-0800'>"procfs_write: write %lu bytes</span></span><span id='textcolor764'><span class='ectt-0800'>\n</span></span><span id='textcolor765'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>, procfs_buffer_size);</span>
|
|
<a id='x1-36112r52'></a><span class='ecrm-0500'>52</span><span class='ectt-0800'> </span><span id='textcolor766'><span class='ectt-0800'>return</span></span><span class='ectt-0800'> procfs_buffer_size;</span>
|
|
<a id='x1-36114r53'></a><span class='ecrm-0500'>53</span><span class='ectt-0800'>}</span>
|
|
<a id='x1-36116r54'></a><span class='ecrm-0500'>54</span><span id='textcolor767'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor768'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> procfs_open(</span><span id='textcolor769'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> inode *inode, </span><span id='textcolor770'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> file *file)</span>
|
|
<a id='x1-36118r55'></a><span class='ecrm-0500'>55</span><span class='ectt-0800'>{</span>
|
|
<a id='x1-36120r56'></a><span class='ecrm-0500'>56</span><span class='ectt-0800'> try_module_get(THIS_MODULE);</span>
|
|
<a id='x1-36122r57'></a><span class='ecrm-0500'>57</span><span class='ectt-0800'> </span><span id='textcolor771'><span class='ectt-0800'>return</span></span><span class='ectt-0800'> 0;</span>
|
|
<a id='x1-36124r58'></a><span class='ecrm-0500'>58</span><span class='ectt-0800'>}</span>
|
|
<a id='x1-36126r59'></a><span class='ecrm-0500'>59</span><span id='textcolor772'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor773'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> procfs_close(</span><span id='textcolor774'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> inode *inode, </span><span id='textcolor775'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> file *file)</span>
|
|
<a id='x1-36128r60'></a><span class='ecrm-0500'>60</span><span class='ectt-0800'>{</span>
|
|
<a id='x1-36130r61'></a><span class='ecrm-0500'>61</span><span class='ectt-0800'> module_put(THIS_MODULE);</span>
|
|
<a id='x1-36132r62'></a><span class='ecrm-0500'>62</span><span class='ectt-0800'> </span><span id='textcolor776'><span class='ectt-0800'>return</span></span><span class='ectt-0800'> 0;</span>
|
|
<a id='x1-36134r63'></a><span class='ecrm-0500'>63</span><span class='ectt-0800'>}</span>
|
|
<a id='x1-36136r64'></a><span class='ecrm-0500'>64</span>
|
|
<a id='x1-36138r65'></a><span class='ecrm-0500'>65</span><span id='textcolor777'><span class='ectt-0800'>#ifdef HAVE_PROC_OPS</span></span>
|
|
<a id='x1-36140r66'></a><span class='ecrm-0500'>66</span><span id='textcolor778'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor779'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> proc_ops file_ops_4_our_proc_file = {</span>
|
|
<a id='x1-36142r67'></a><span class='ecrm-0500'>67</span><span class='ectt-0800'> .proc_read = procfs_read,</span>
|
|
<a id='x1-36144r68'></a><span class='ecrm-0500'>68</span><span class='ectt-0800'> .proc_write = procfs_write,</span>
|
|
<a id='x1-36146r69'></a><span class='ecrm-0500'>69</span><span class='ectt-0800'> .proc_open = procfs_open,</span>
|
|
<a id='x1-36148r70'></a><span class='ecrm-0500'>70</span><span class='ectt-0800'> .proc_release = procfs_close,</span>
|
|
<a id='x1-36150r71'></a><span class='ecrm-0500'>71</span><span class='ectt-0800'>};</span>
|
|
<a id='x1-36152r72'></a><span class='ecrm-0500'>72</span><span id='textcolor780'><span class='ectt-0800'>#else</span></span>
|
|
<a id='x1-36154r73'></a><span class='ecrm-0500'>73</span><span id='textcolor781'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor782'><span class='ectt-0800'>const</span></span><span class='ectt-0800'> </span><span id='textcolor783'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> file_operations file_ops_4_our_proc_file = {</span>
|
|
<a id='x1-36156r74'></a><span class='ecrm-0500'>74</span><span class='ectt-0800'> .read = procfs_read,</span>
|
|
<a id='x1-36158r75'></a><span class='ecrm-0500'>75</span><span class='ectt-0800'> .write = procfs_write,</span>
|
|
<a id='x1-36160r76'></a><span class='ecrm-0500'>76</span><span class='ectt-0800'> .open = procfs_open,</span>
|
|
<a id='x1-36162r77'></a><span class='ecrm-0500'>77</span><span class='ectt-0800'> .release = procfs_close,</span>
|
|
<a id='x1-36164r78'></a><span class='ecrm-0500'>78</span><span class='ectt-0800'>};</span>
|
|
<a id='x1-36166r79'></a><span class='ecrm-0500'>79</span><span id='textcolor784'><span class='ectt-0800'>#endif</span></span>
|
|
<a id='x1-36168r80'></a><span class='ecrm-0500'>80</span>
|
|
<a id='x1-36170r81'></a><span class='ecrm-0500'>81</span><span id='textcolor785'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor786'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> __init procfs3_init(</span><span id='textcolor787'><span class='ectt-0800'>void</span></span><span class='ectt-0800'>)</span>
|
|
<a id='x1-36172r82'></a><span class='ecrm-0500'>82</span><span class='ectt-0800'>{</span>
|
|
<a id='x1-36174r83'></a><span class='ecrm-0500'>83</span><span class='ectt-0800'> our_proc_file = proc_create(PROCFS_ENTRY_FILENAME, 0644, NULL,</span>
|
|
<a id='x1-36176r84'></a><span class='ecrm-0500'>84</span><span class='ectt-0800'> &file_ops_4_our_proc_file);</span>
|
|
<a id='x1-36178r85'></a><span class='ecrm-0500'>85</span><span class='ectt-0800'> </span><span id='textcolor788'><span class='ectt-0800'>if</span></span><span class='ectt-0800'> (our_proc_file == NULL) {</span>
|
|
<a id='x1-36180r86'></a><span class='ecrm-0500'>86</span><span class='ectt-0800'> remove_proc_entry(PROCFS_ENTRY_FILENAME, NULL);</span>
|
|
<a id='x1-36182r87'></a><span class='ecrm-0500'>87</span><span class='ectt-0800'> pr_debug(</span><span id='textcolor789'><span class='ectt-0800'>"Error: Could not initialize /proc/%s</span></span><span id='textcolor790'><span class='ectt-0800'>\n</span></span><span id='textcolor791'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>,</span>
|
|
<a id='x1-36184r88'></a><span class='ecrm-0500'>88</span><span class='ectt-0800'> PROCFS_ENTRY_FILENAME);</span>
|
|
<a id='x1-36186r89'></a><span class='ecrm-0500'>89</span><span class='ectt-0800'> </span><span id='textcolor792'><span class='ectt-0800'>return</span></span><span class='ectt-0800'> -ENOMEM;</span>
|
|
<a id='x1-36188r90'></a><span class='ecrm-0500'>90</span><span class='ectt-0800'> }</span>
|
|
<a id='x1-36190r91'></a><span class='ecrm-0500'>91</span><span class='ectt-0800'> proc_set_size(our_proc_file, 80);</span>
|
|
<a id='x1-36192r92'></a><span class='ecrm-0500'>92</span><span class='ectt-0800'> proc_set_user(our_proc_file, GLOBAL_ROOT_UID, GLOBAL_ROOT_GID);</span>
|
|
<a id='x1-36194r93'></a><span class='ecrm-0500'>93</span>
|
|
<a id='x1-36196r94'></a><span class='ecrm-0500'>94</span><span class='ectt-0800'> pr_debug(</span><span id='textcolor793'><span class='ectt-0800'>"/proc/%s created</span></span><span id='textcolor794'><span class='ectt-0800'>\n</span></span><span id='textcolor795'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>, PROCFS_ENTRY_FILENAME);</span>
|
|
<a id='x1-36198r95'></a><span class='ecrm-0500'>95</span><span class='ectt-0800'> </span><span id='textcolor796'><span class='ectt-0800'>return</span></span><span class='ectt-0800'> 0;</span>
|
|
<a id='x1-36200r96'></a><span class='ecrm-0500'>96</span><span class='ectt-0800'>}</span>
|
|
<a id='x1-36202r97'></a><span class='ecrm-0500'>97</span>
|
|
<a id='x1-36204r98'></a><span class='ecrm-0500'>98</span><span id='textcolor797'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor798'><span class='ectt-0800'>void</span></span><span class='ectt-0800'> __exit procfs3_exit(</span><span id='textcolor799'><span class='ectt-0800'>void</span></span><span class='ectt-0800'>)</span>
|
|
<a id='x1-36206r99'></a><span class='ecrm-0500'>99</span><span class='ectt-0800'>{</span>
|
|
<a id='x1-36208r100'></a><span class='ecrm-0500'>100</span><span class='ectt-0800'> remove_proc_entry(PROCFS_ENTRY_FILENAME, NULL);</span>
|
|
<a id='x1-36210r101'></a><span class='ecrm-0500'>101</span><span class='ectt-0800'> pr_debug(</span><span id='textcolor800'><span class='ectt-0800'>"/proc/%s removed</span></span><span id='textcolor801'><span class='ectt-0800'>\n</span></span><span id='textcolor802'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>, PROCFS_ENTRY_FILENAME);</span>
|
|
<a id='x1-36212r102'></a><span class='ecrm-0500'>102</span><span class='ectt-0800'>}</span>
|
|
<a id='x1-36214r103'></a><span class='ecrm-0500'>103</span>
|
|
<a id='x1-36216r104'></a><span class='ecrm-0500'>104</span><span class='ectt-0800'>module_init(procfs3_init);</span>
|
|
<a id='x1-36218r105'></a><span class='ecrm-0500'>105</span><span class='ectt-0800'>module_exit(procfs3_exit);</span>
|
|
<a id='x1-36220r106'></a><span class='ecrm-0500'>106</span>
|
|
<a id='x1-36222r107'></a><span class='ecrm-0500'>107</span><span class='ectt-0800'>MODULE_LICENSE(</span><span id='textcolor803'><span class='ectt-0800'>"GPL"</span></span><span class='ectt-0800'>);</span></pre>
|
|
<!-- l. 1033 --><p class='indent'> Still hungry for procfs examples? Well, first of all keep in mind, there are rumors
|
|
around, claiming that procfs is on its way out, consider using <span class='obeylines-h'><span class='verb'><span class='ectt-1000'>sysfs</span></span></span> instead. Consider
|
|
using this mechanism, in case you want to document something kernel related
|
|
yourself.
|
|
</p><!-- l. 1037 --><p class='noindent'>
|
|
</p>
|
|
<h4 class='subsectionHead' id='manage-proc-file-with-seqfile'><span class='titlemark'>7.4 </span> <a id='x1-370007.4'></a>Manage /proc file with seq_file</h4>
|
|
<!-- l. 1039 --><p class='noindent'>As we have seen, writing a <span class='obeylines-h'><span class='verb'><span class='ectt-1000'>/proc</span></span></span> file may be quite “complex”.
|
|
So to help people writting <span class='obeylines-h'><span class='verb'><span class='ectt-1000'>/proc</span></span></span> file, there is an API named
|
|
<code> <span class='ectt-1000'>seq_file</span>
|
|
</code> that helps formating a <span class='obeylines-h'><span class='verb'><span class='ectt-1000'>/proc</span></span></span> file for output. It is based on sequence, which is composed of
|
|
3 functions: <code> <span class='ectt-1000'>start()</span>
|
|
</code>, <code> <span class='ectt-1000'>next()</span>
|
|
</code>, and <code> <span class='ectt-1000'>stop()</span>
|
|
</code>. The <code> <span class='ectt-1000'>seq_file</span>
|
|
</code> API starts a sequence when a user read the <span class='obeylines-h'><span class='verb'><span class='ectt-1000'>/proc</span></span></span> file.
|
|
</p><!-- l. 1044 --><p class='indent'> A sequence begins with the call of the function
|
|
<code> <span class='ectt-1000'>start()</span>
|
|
</code>. If the return is a non <code> <span class='ectt-1000'>NULL</span>
|
|
</code> value, the function <code> <span class='ectt-1000'>next()</span>
|
|
</code> is called. This function is an iterator, the goal is to go through all the data. Each
|
|
|
|
|
|
|
|
time <code> <span class='ectt-1000'>next()</span>
|
|
</code> is called, the function <code> <span class='ectt-1000'>show()</span>
|
|
</code> is also called. It writes data values in the buffer read by the user. The function
|
|
<code> <span class='ectt-1000'>next()</span>
|
|
</code> is called until it returns <code> <span class='ectt-1000'>NULL</span>
|
|
</code>. The sequence ends when <code> <span class='ectt-1000'>next()</span>
|
|
</code> returns <code> <span class='ectt-1000'>NULL</span>
|
|
</code>, then the function <code> <span class='ectt-1000'>stop()</span>
|
|
</code> is called.
|
|
</p><!-- l. 1052 --><p class='indent'> BE CAREFUL: when a sequence is finished, another one starts. That means that at the end
|
|
of function <code> <span class='ectt-1000'>stop()</span>
|
|
</code>, the function <code> <span class='ectt-1000'>start()</span>
|
|
</code> is called again. This loop finishes when the function
|
|
<code> <span class='ectt-1000'>start()</span>
|
|
</code> returns <code> <span class='ectt-1000'>NULL</span>
|
|
</code>. You can see a scheme of this in the Figure <a href='#ignorespaces-how-seqfile-works'>1<!-- tex4ht:ref: img:seqfile --></a>.
|
|
</p>
|
|
<figure class='figure' id='ignorespaces-how-seqfile-works'>
|
|
|
|
|
|
|
|
|
|
<a id='x1-37020r1'></a>
|
|
|
|
|
|
|
|
<!-- l. 1059 --><p class='noindent'><img alt='srYrsNNYtaeenetoooertusetupstrxr((ntn))( tis)istrr teeaNreNatUaUtmLtLmeLmLen?e?ntntt ' src='lkmpg-for-ht1x.svg' />
|
|
</p>
|
|
<figcaption class='caption'><span class='id'>Figure 1:</span><span class='content'>How seq_file works</span></figcaption><!-- tex4ht:label?: x1-37020r1 -->
|
|
|
|
|
|
|
|
</figure>
|
|
<!-- l. 1079 --><p class='indent'> The <code> <span class='ectt-1000'>seq_file</span>
|
|
</code> provides basic functions for <code> <span class='ectt-1000'>proc_ops</span>
|
|
</code>, such as <code> <span class='ectt-1000'>seq_read</span>
|
|
</code>, <code> <span class='ectt-1000'>seq_lseek</span>
|
|
</code>, and some others. But nothing to write in the <span class='obeylines-h'><span class='verb'><span class='ectt-1000'>/proc</span></span></span> file. Of course, you can still use
|
|
the same way as in the previous example.
|
|
</p>
|
|
<pre class='fancyvrb' id='fancyvrb41'><a id='x1-37026r1'></a><span class='ecrm-0500'>1</span><span id='textcolor804'><span class='ectt-0800'>/*</span></span>
|
|
<a id='x1-37028r2'></a><span class='ecrm-0500'>2</span><span id='textcolor805'><span class='ectt-0800'> * procfs4.c - create a "file" in /proc</span></span>
|
|
<a id='x1-37030r3'></a><span class='ecrm-0500'>3</span><span id='textcolor806'><span class='ectt-0800'> * This program uses the seq_file library to manage the /proc file.</span></span>
|
|
<a id='x1-37032r4'></a><span class='ecrm-0500'>4</span><span id='textcolor807'><span class='ectt-0800'> */</span></span>
|
|
<a id='x1-37034r5'></a><span class='ecrm-0500'>5</span>
|
|
<a id='x1-37036r6'></a><span class='ecrm-0500'>6</span><span id='textcolor808'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor809'><span class='ectt-0800'><linux/kernel.h> /* We are doing kernel work */</span></span>
|
|
<a id='x1-37038r7'></a><span class='ecrm-0500'>7</span><span id='textcolor810'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor811'><span class='ectt-0800'><linux/module.h> /* Specifically, a module */</span></span>
|
|
<a id='x1-37040r8'></a><span class='ecrm-0500'>8</span><span id='textcolor812'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor813'><span class='ectt-0800'><linux/proc_fs.h> /* Necessary because we use proc fs */</span></span>
|
|
<a id='x1-37042r9'></a><span class='ecrm-0500'>9</span><span id='textcolor814'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor815'><span class='ectt-0800'><linux/seq_file.h> /* for seq_file */</span></span>
|
|
<a id='x1-37044r10'></a><span class='ecrm-0500'>10</span><span id='textcolor816'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor817'><span class='ectt-0800'><linux/version.h></span></span>
|
|
<a id='x1-37046r11'></a><span class='ecrm-0500'>11</span>
|
|
<a id='x1-37048r12'></a><span class='ecrm-0500'>12</span><span id='textcolor818'><span class='ectt-0800'>#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 6, 0)</span></span>
|
|
<a id='x1-37050r13'></a><span class='ecrm-0500'>13</span><span id='textcolor819'><span class='ectt-0800'>#define HAVE_PROC_OPS</span></span>
|
|
<a id='x1-37052r14'></a><span class='ecrm-0500'>14</span><span id='textcolor820'><span class='ectt-0800'>#endif</span></span>
|
|
<a id='x1-37054r15'></a><span class='ecrm-0500'>15</span>
|
|
<a id='x1-37056r16'></a><span class='ecrm-0500'>16</span><span id='textcolor821'><span class='ectt-0800'>#define PROC_NAME "iter"</span></span>
|
|
<a id='x1-37058r17'></a><span class='ecrm-0500'>17</span>
|
|
<a id='x1-37060r18'></a><span class='ecrm-0500'>18</span><span id='textcolor822'><span class='ectt-0800'>/* This function is called at the beginning of a sequence.</span></span>
|
|
<a id='x1-37062r19'></a><span class='ecrm-0500'>19</span><span id='textcolor823'><span class='ectt-0800'> * ie, when:</span></span>
|
|
<a id='x1-37064r20'></a><span class='ecrm-0500'>20</span><span id='textcolor824'><span class='ectt-0800'> * - the /proc file is read (first time)</span></span>
|
|
<a id='x1-37066r21'></a><span class='ecrm-0500'>21</span><span id='textcolor825'><span class='ectt-0800'> * - after the function stop (end of sequence)</span></span>
|
|
<a id='x1-37068r22'></a><span class='ecrm-0500'>22</span><span id='textcolor826'><span class='ectt-0800'> */</span></span>
|
|
<a id='x1-37070r23'></a><span class='ecrm-0500'>23</span><span id='textcolor827'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor828'><span class='ectt-0800'>void</span></span><span class='ectt-0800'> *my_seq_start(</span><span id='textcolor829'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> seq_file *s, loff_t *pos)</span>
|
|
<a id='x1-37072r24'></a><span class='ecrm-0500'>24</span><span class='ectt-0800'>{</span>
|
|
<a id='x1-37074r25'></a><span class='ecrm-0500'>25</span><span class='ectt-0800'> </span><span id='textcolor830'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor831'><span class='ectt-0800'>unsigned</span></span><span class='ectt-0800'> </span><span id='textcolor832'><span class='ectt-0800'>long</span></span><span class='ectt-0800'> counter = 0;</span>
|
|
<a id='x1-37076r26'></a><span class='ecrm-0500'>26</span>
|
|
<a id='x1-37078r27'></a><span class='ecrm-0500'>27</span><span class='ectt-0800'> </span><span id='textcolor833'><span class='ectt-0800'>/* beginning a new sequence? */</span></span>
|
|
<a id='x1-37080r28'></a><span class='ecrm-0500'>28</span><span class='ectt-0800'> </span><span id='textcolor834'><span class='ectt-0800'>if</span></span><span class='ectt-0800'> (*pos == 0) {</span>
|
|
<a id='x1-37082r29'></a><span class='ecrm-0500'>29</span><span class='ectt-0800'> </span><span id='textcolor835'><span class='ectt-0800'>/* yes => return a non null value to begin the sequence */</span></span>
|
|
<a id='x1-37084r30'></a><span class='ecrm-0500'>30</span><span class='ectt-0800'> </span><span id='textcolor836'><span class='ectt-0800'>return</span></span><span class='ectt-0800'> &counter;</span>
|
|
<a id='x1-37086r31'></a><span class='ecrm-0500'>31</span><span class='ectt-0800'> }</span>
|
|
<a id='x1-37088r32'></a><span class='ecrm-0500'>32</span>
|
|
<a id='x1-37090r33'></a><span class='ecrm-0500'>33</span><span class='ectt-0800'> </span><span id='textcolor837'><span class='ectt-0800'>/* no => it is the end of the sequence, return end to stop reading */</span></span>
|
|
<a id='x1-37092r34'></a><span class='ecrm-0500'>34</span><span class='ectt-0800'> *pos = 0;</span>
|
|
<a id='x1-37094r35'></a><span class='ecrm-0500'>35</span><span class='ectt-0800'> </span><span id='textcolor838'><span class='ectt-0800'>return</span></span><span class='ectt-0800'> NULL;</span>
|
|
<a id='x1-37096r36'></a><span class='ecrm-0500'>36</span><span class='ectt-0800'>}</span>
|
|
<a id='x1-37098r37'></a><span class='ecrm-0500'>37</span>
|
|
<a id='x1-37100r38'></a><span class='ecrm-0500'>38</span><span id='textcolor839'><span class='ectt-0800'>/* This function is called after the beginning of a sequence.</span></span>
|
|
<a id='x1-37102r39'></a><span class='ecrm-0500'>39</span><span id='textcolor840'><span class='ectt-0800'> * It is called untill the return is NULL (this ends the sequence).</span></span>
|
|
<a id='x1-37104r40'></a><span class='ecrm-0500'>40</span><span id='textcolor841'><span class='ectt-0800'> */</span></span>
|
|
<a id='x1-37106r41'></a><span class='ecrm-0500'>41</span><span id='textcolor842'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor843'><span class='ectt-0800'>void</span></span><span class='ectt-0800'> *my_seq_next(</span><span id='textcolor844'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> seq_file *s, </span><span id='textcolor845'><span class='ectt-0800'>void</span></span><span class='ectt-0800'> *v, loff_t *pos)</span>
|
|
<a id='x1-37108r42'></a><span class='ecrm-0500'>42</span><span class='ectt-0800'>{</span>
|
|
<a id='x1-37110r43'></a><span class='ecrm-0500'>43</span><span class='ectt-0800'> </span><span id='textcolor846'><span class='ectt-0800'>unsigned</span></span><span class='ectt-0800'> </span><span id='textcolor847'><span class='ectt-0800'>long</span></span><span class='ectt-0800'> *tmp_v = (</span><span id='textcolor848'><span class='ectt-0800'>unsigned</span></span><span class='ectt-0800'> </span><span id='textcolor849'><span class='ectt-0800'>long</span></span><span class='ectt-0800'> *)v;</span>
|
|
<a id='x1-37112r44'></a><span class='ecrm-0500'>44</span><span class='ectt-0800'> (*tmp_v)++;</span>
|
|
<a id='x1-37114r45'></a><span class='ecrm-0500'>45</span><span class='ectt-0800'> (*pos)++;</span>
|
|
<a id='x1-37116r46'></a><span class='ecrm-0500'>46</span><span class='ectt-0800'> </span><span id='textcolor850'><span class='ectt-0800'>return</span></span><span class='ectt-0800'> NULL;</span>
|
|
<a id='x1-37118r47'></a><span class='ecrm-0500'>47</span><span class='ectt-0800'>}</span>
|
|
<a id='x1-37120r48'></a><span class='ecrm-0500'>48</span>
|
|
<a id='x1-37122r49'></a><span class='ecrm-0500'>49</span><span id='textcolor851'><span class='ectt-0800'>/* This function is called at the end of a sequence. */</span></span>
|
|
<a id='x1-37124r50'></a><span class='ecrm-0500'>50</span><span id='textcolor852'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor853'><span class='ectt-0800'>void</span></span><span class='ectt-0800'> my_seq_stop(</span><span id='textcolor854'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> seq_file *s, </span><span id='textcolor855'><span class='ectt-0800'>void</span></span><span class='ectt-0800'> *v)</span>
|
|
<a id='x1-37126r51'></a><span class='ecrm-0500'>51</span><span class='ectt-0800'>{</span>
|
|
<a id='x1-37128r52'></a><span class='ecrm-0500'>52</span><span class='ectt-0800'> </span><span id='textcolor856'><span class='ectt-0800'>/* nothing to do, we use a static value in start() */</span></span>
|
|
<a id='x1-37130r53'></a><span class='ecrm-0500'>53</span><span class='ectt-0800'>}</span>
|
|
<a id='x1-37132r54'></a><span class='ecrm-0500'>54</span>
|
|
<a id='x1-37134r55'></a><span class='ecrm-0500'>55</span><span id='textcolor857'><span class='ectt-0800'>/* This function is called for each "step" of a sequence. */</span></span>
|
|
<a id='x1-37136r56'></a><span class='ecrm-0500'>56</span><span id='textcolor858'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor859'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> my_seq_show(</span><span id='textcolor860'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> seq_file *s, </span><span id='textcolor861'><span class='ectt-0800'>void</span></span><span class='ectt-0800'> *v)</span>
|
|
<a id='x1-37138r57'></a><span class='ecrm-0500'>57</span><span class='ectt-0800'>{</span>
|
|
<a id='x1-37140r58'></a><span class='ecrm-0500'>58</span><span class='ectt-0800'> loff_t *spos = (loff_t *)v;</span>
|
|
<a id='x1-37142r59'></a><span class='ecrm-0500'>59</span>
|
|
<a id='x1-37144r60'></a><span class='ecrm-0500'>60</span><span class='ectt-0800'> seq_printf(s, </span><span id='textcolor862'><span class='ectt-0800'>"%Ld</span></span><span id='textcolor863'><span class='ectt-0800'>\n</span></span><span id='textcolor864'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>, *spos);</span>
|
|
<a id='x1-37146r61'></a><span class='ecrm-0500'>61</span><span class='ectt-0800'> </span><span id='textcolor865'><span class='ectt-0800'>return</span></span><span class='ectt-0800'> 0;</span>
|
|
<a id='x1-37148r62'></a><span class='ecrm-0500'>62</span><span class='ectt-0800'>}</span>
|
|
<a id='x1-37150r63'></a><span class='ecrm-0500'>63</span>
|
|
<a id='x1-37152r64'></a><span class='ecrm-0500'>64</span><span id='textcolor866'><span class='ectt-0800'>/* This structure gather "function" to manage the sequence */</span></span>
|
|
<a id='x1-37154r65'></a><span class='ecrm-0500'>65</span><span id='textcolor867'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor868'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> seq_operations my_seq_ops = {</span>
|
|
<a id='x1-37156r66'></a><span class='ecrm-0500'>66</span><span class='ectt-0800'> .start = my_seq_start,</span>
|
|
<a id='x1-37158r67'></a><span class='ecrm-0500'>67</span><span class='ectt-0800'> .next = my_seq_next,</span>
|
|
<a id='x1-37160r68'></a><span class='ecrm-0500'>68</span><span class='ectt-0800'> .stop = my_seq_stop,</span>
|
|
<a id='x1-37162r69'></a><span class='ecrm-0500'>69</span><span class='ectt-0800'> .show = my_seq_show,</span>
|
|
<a id='x1-37164r70'></a><span class='ecrm-0500'>70</span><span class='ectt-0800'>};</span>
|
|
<a id='x1-37166r71'></a><span class='ecrm-0500'>71</span>
|
|
<a id='x1-37168r72'></a><span class='ecrm-0500'>72</span><span id='textcolor869'><span class='ectt-0800'>/* This function is called when the /proc file is open. */</span></span>
|
|
<a id='x1-37170r73'></a><span class='ecrm-0500'>73</span><span id='textcolor870'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor871'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> my_open(</span><span id='textcolor872'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> inode *inode, </span><span id='textcolor873'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> file *file)</span>
|
|
<a id='x1-37172r74'></a><span class='ecrm-0500'>74</span><span class='ectt-0800'>{</span>
|
|
<a id='x1-37174r75'></a><span class='ecrm-0500'>75</span><span class='ectt-0800'> </span><span id='textcolor874'><span class='ectt-0800'>return</span></span><span class='ectt-0800'> seq_open(file, &my_seq_ops);</span>
|
|
<a id='x1-37176r76'></a><span class='ecrm-0500'>76</span><span class='ectt-0800'>};</span>
|
|
<a id='x1-37178r77'></a><span class='ecrm-0500'>77</span>
|
|
<a id='x1-37180r78'></a><span class='ecrm-0500'>78</span><span id='textcolor875'><span class='ectt-0800'>/* This structure gather "function" that manage the /proc file */</span></span>
|
|
<a id='x1-37182r79'></a><span class='ecrm-0500'>79</span><span id='textcolor876'><span class='ectt-0800'>#ifdef HAVE_PROC_OPS</span></span>
|
|
<a id='x1-37184r80'></a><span class='ecrm-0500'>80</span><span id='textcolor877'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor878'><span class='ectt-0800'>const</span></span><span class='ectt-0800'> </span><span id='textcolor879'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> proc_ops my_file_ops = {</span>
|
|
<a id='x1-37186r81'></a><span class='ecrm-0500'>81</span><span class='ectt-0800'> .proc_open = my_open,</span>
|
|
<a id='x1-37188r82'></a><span class='ecrm-0500'>82</span><span class='ectt-0800'> .proc_read = seq_read,</span>
|
|
<a id='x1-37190r83'></a><span class='ecrm-0500'>83</span><span class='ectt-0800'> .proc_lseek = seq_lseek,</span>
|
|
<a id='x1-37192r84'></a><span class='ecrm-0500'>84</span><span class='ectt-0800'> .proc_release = seq_release,</span>
|
|
<a id='x1-37194r85'></a><span class='ecrm-0500'>85</span><span class='ectt-0800'>};</span>
|
|
<a id='x1-37196r86'></a><span class='ecrm-0500'>86</span><span id='textcolor880'><span class='ectt-0800'>#else</span></span>
|
|
<a id='x1-37198r87'></a><span class='ecrm-0500'>87</span><span id='textcolor881'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor882'><span class='ectt-0800'>const</span></span><span class='ectt-0800'> </span><span id='textcolor883'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> file_operations my_file_ops = {</span>
|
|
<a id='x1-37200r88'></a><span class='ecrm-0500'>88</span><span class='ectt-0800'> .open = my_open,</span>
|
|
<a id='x1-37202r89'></a><span class='ecrm-0500'>89</span><span class='ectt-0800'> .read = seq_read,</span>
|
|
<a id='x1-37204r90'></a><span class='ecrm-0500'>90</span><span class='ectt-0800'> .llseek = seq_lseek,</span>
|
|
<a id='x1-37206r91'></a><span class='ecrm-0500'>91</span><span class='ectt-0800'> .release = seq_release,</span>
|
|
<a id='x1-37208r92'></a><span class='ecrm-0500'>92</span><span class='ectt-0800'>};</span>
|
|
<a id='x1-37210r93'></a><span class='ecrm-0500'>93</span><span id='textcolor884'><span class='ectt-0800'>#endif</span></span>
|
|
<a id='x1-37212r94'></a><span class='ecrm-0500'>94</span>
|
|
<a id='x1-37214r95'></a><span class='ecrm-0500'>95</span><span id='textcolor885'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor886'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> __init procfs4_init(</span><span id='textcolor887'><span class='ectt-0800'>void</span></span><span class='ectt-0800'>)</span>
|
|
<a id='x1-37216r96'></a><span class='ecrm-0500'>96</span><span class='ectt-0800'>{</span>
|
|
<a id='x1-37218r97'></a><span class='ecrm-0500'>97</span><span class='ectt-0800'> </span><span id='textcolor888'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> proc_dir_entry *entry;</span>
|
|
<a id='x1-37220r98'></a><span class='ecrm-0500'>98</span>
|
|
<a id='x1-37222r99'></a><span class='ecrm-0500'>99</span><span class='ectt-0800'> entry = proc_create(PROC_NAME, 0, NULL, &my_file_ops);</span>
|
|
<a id='x1-37224r100'></a><span class='ecrm-0500'>100</span><span class='ectt-0800'> </span><span id='textcolor889'><span class='ectt-0800'>if</span></span><span class='ectt-0800'> (entry == NULL) {</span>
|
|
<a id='x1-37226r101'></a><span class='ecrm-0500'>101</span><span class='ectt-0800'> remove_proc_entry(PROC_NAME, NULL);</span>
|
|
<a id='x1-37228r102'></a><span class='ecrm-0500'>102</span><span class='ectt-0800'> pr_debug(</span><span id='textcolor890'><span class='ectt-0800'>"Error: Could not initialize /proc/%s</span></span><span id='textcolor891'><span class='ectt-0800'>\n</span></span><span id='textcolor892'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>, PROC_NAME);</span>
|
|
<a id='x1-37230r103'></a><span class='ecrm-0500'>103</span><span class='ectt-0800'> </span><span id='textcolor893'><span class='ectt-0800'>return</span></span><span class='ectt-0800'> -ENOMEM;</span>
|
|
<a id='x1-37232r104'></a><span class='ecrm-0500'>104</span><span class='ectt-0800'> }</span>
|
|
<a id='x1-37234r105'></a><span class='ecrm-0500'>105</span>
|
|
<a id='x1-37236r106'></a><span class='ecrm-0500'>106</span><span class='ectt-0800'> </span><span id='textcolor894'><span class='ectt-0800'>return</span></span><span class='ectt-0800'> 0;</span>
|
|
<a id='x1-37238r107'></a><span class='ecrm-0500'>107</span><span class='ectt-0800'>}</span>
|
|
<a id='x1-37240r108'></a><span class='ecrm-0500'>108</span>
|
|
<a id='x1-37242r109'></a><span class='ecrm-0500'>109</span><span id='textcolor895'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor896'><span class='ectt-0800'>void</span></span><span class='ectt-0800'> __exit procfs4_exit(</span><span id='textcolor897'><span class='ectt-0800'>void</span></span><span class='ectt-0800'>)</span>
|
|
<a id='x1-37244r110'></a><span class='ecrm-0500'>110</span><span class='ectt-0800'>{</span>
|
|
<a id='x1-37246r111'></a><span class='ecrm-0500'>111</span><span class='ectt-0800'> remove_proc_entry(PROC_NAME, NULL);</span>
|
|
<a id='x1-37248r112'></a><span class='ecrm-0500'>112</span><span class='ectt-0800'> pr_debug(</span><span id='textcolor898'><span class='ectt-0800'>"/proc/%s removed</span></span><span id='textcolor899'><span class='ectt-0800'>\n</span></span><span id='textcolor900'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>, PROC_NAME);</span>
|
|
<a id='x1-37250r113'></a><span class='ecrm-0500'>113</span><span class='ectt-0800'>}</span>
|
|
<a id='x1-37252r114'></a><span class='ecrm-0500'>114</span>
|
|
<a id='x1-37254r115'></a><span class='ecrm-0500'>115</span><span class='ectt-0800'>module_init(procfs4_init);</span>
|
|
<a id='x1-37256r116'></a><span class='ecrm-0500'>116</span><span class='ectt-0800'>module_exit(procfs4_exit);</span>
|
|
<a id='x1-37258r117'></a><span class='ecrm-0500'>117</span>
|
|
<a id='x1-37260r118'></a><span class='ecrm-0500'>118</span><span class='ectt-0800'>MODULE_LICENSE(</span><span id='textcolor901'><span class='ectt-0800'>"GPL"</span></span><span class='ectt-0800'>);</span></pre>
|
|
<!-- l. 1085 --><p class='indent'> If you want more information, you can read this web page:
|
|
</p>
|
|
<ul class='itemize1'>
|
|
<li class='itemize'><a class='url' href='https://lwn.net/Articles/22355/'><span class='ectt-1000'>https://lwn.net/Articles/22355/</span></a>
|
|
</li>
|
|
<li class='itemize'><a class='url' href='https://kernelnewbies.org/Documents/SeqFileHowTo'><span class='ectt-1000'>https://kernelnewbies.org/Documents/SeqFileHowTo</span></a></li></ul>
|
|
<!-- l. 1092 --><p class='indent'> You can also read the code of <a href='https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/tree/fs/seq_file.c'>fs/seq_file.c</a> in the linux kernel.
|
|
</p>
|
|
<h3 class='sectionHead' id='sysfs-interacting-with-your-module'><span class='titlemark'>8 </span> <a id='x1-380008'></a>sysfs: Interacting with your module</h3>
|
|
<!-- l. 1096 --><p class='noindent'><span class='ecti-1000'>sysfs </span>allows you to interact with the running kernel from userspace by reading or
|
|
setting variables inside of modules. This can be useful for debugging purposes, or just
|
|
as an interface for applications or scripts. You can find sysfs directories and files
|
|
under the <span class='obeylines-h'><span class='verb'><span class='ectt-1000'>/sys</span></span></span> directory on your system.
|
|
</p><!-- l. 1 --><p class='indent'>
|
|
</p>
|
|
<pre class='fancyvrb' id='fancyvrb42'><a id='x1-38003r1'></a><span class='ecrm-0500'>1</span><span class='ectt-1000'>ls -l /sys</span></pre>
|
|
<!-- l. 1104 --><p class='indent'> An example of a hello world module which includes the creation of a variable
|
|
accessible via sysfs is given below.
|
|
</p><!-- l. 1 --><p class='indent'>
|
|
</p>
|
|
<pre class='fancyvrb' id='fancyvrb43'><a id='x1-38005r1'></a><span class='ecrm-0500'>1</span><span id='textcolor902'><span class='ectt-0800'>/*</span></span>
|
|
<a id='x1-38007r2'></a><span class='ecrm-0500'>2</span><span id='textcolor903'><span class='ectt-0800'> * hello-sysfs.c sysfs example</span></span>
|
|
<a id='x1-38009r3'></a><span class='ecrm-0500'>3</span><span id='textcolor904'><span class='ectt-0800'> */</span></span>
|
|
<a id='x1-38011r4'></a><span class='ecrm-0500'>4</span><span id='textcolor905'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor906'><span class='ectt-0800'><linux/fs.h></span></span>
|
|
<a id='x1-38013r5'></a><span class='ecrm-0500'>5</span><span id='textcolor907'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor908'><span class='ectt-0800'><linux/init.h></span></span>
|
|
<a id='x1-38015r6'></a><span class='ecrm-0500'>6</span><span id='textcolor909'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor910'><span class='ectt-0800'><linux/kobject.h></span></span>
|
|
<a id='x1-38017r7'></a><span class='ecrm-0500'>7</span><span id='textcolor911'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor912'><span class='ectt-0800'><linux/module.h></span></span>
|
|
<a id='x1-38019r8'></a><span class='ecrm-0500'>8</span><span id='textcolor913'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor914'><span class='ectt-0800'><linux/string.h></span></span>
|
|
<a id='x1-38021r9'></a><span class='ecrm-0500'>9</span><span id='textcolor915'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor916'><span class='ectt-0800'><linux/sysfs.h></span></span>
|
|
<a id='x1-38023r10'></a><span class='ecrm-0500'>10</span>
|
|
<a id='x1-38025r11'></a><span class='ecrm-0500'>11</span><span id='textcolor917'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor918'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> kobject *mymodule;</span>
|
|
<a id='x1-38027r12'></a><span class='ecrm-0500'>12</span>
|
|
<a id='x1-38029r13'></a><span class='ecrm-0500'>13</span><span id='textcolor919'><span class='ectt-0800'>/* the variable you want to be able to change */</span></span>
|
|
<a id='x1-38031r14'></a><span class='ecrm-0500'>14</span><span id='textcolor920'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor921'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> myvariable = 0;</span>
|
|
<a id='x1-38033r15'></a><span class='ecrm-0500'>15</span>
|
|
<a id='x1-38035r16'></a><span class='ecrm-0500'>16</span><span id='textcolor922'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor923'><span class='ectt-0800'>ssize_t</span></span><span class='ectt-0800'> myvariable_show(</span><span id='textcolor924'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> kobject *kobj,</span>
|
|
<a id='x1-38037r17'></a><span class='ecrm-0500'>17</span><span class='ectt-0800'> </span><span id='textcolor925'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> kobj_attribute *attr, </span><span id='textcolor926'><span class='ectt-0800'>char</span></span><span class='ectt-0800'> *buf)</span>
|
|
<a id='x1-38039r18'></a><span class='ecrm-0500'>18</span><span class='ectt-0800'>{</span>
|
|
<a id='x1-38041r19'></a><span class='ecrm-0500'>19</span><span class='ectt-0800'> </span><span id='textcolor927'><span class='ectt-0800'>return</span></span><span class='ectt-0800'> sprintf(buf, </span><span id='textcolor928'><span class='ectt-0800'>"%d</span></span><span id='textcolor929'><span class='ectt-0800'>\n</span></span><span id='textcolor930'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>, myvariable);</span>
|
|
<a id='x1-38043r20'></a><span class='ecrm-0500'>20</span><span class='ectt-0800'>}</span>
|
|
<a id='x1-38045r21'></a><span class='ecrm-0500'>21</span>
|
|
<a id='x1-38047r22'></a><span class='ecrm-0500'>22</span><span id='textcolor931'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor932'><span class='ectt-0800'>ssize_t</span></span><span class='ectt-0800'> myvariable_store(</span><span id='textcolor933'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> kobject *kobj,</span>
|
|
<a id='x1-38049r23'></a><span class='ecrm-0500'>23</span><span class='ectt-0800'> </span><span id='textcolor934'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> kobj_attribute *attr, </span><span id='textcolor935'><span class='ectt-0800'>char</span></span><span class='ectt-0800'> *buf,</span>
|
|
<a id='x1-38051r24'></a><span class='ecrm-0500'>24</span><span class='ectt-0800'> </span><span id='textcolor936'><span class='ectt-0800'>size_t</span></span><span class='ectt-0800'> count)</span>
|
|
<a id='x1-38053r25'></a><span class='ecrm-0500'>25</span><span class='ectt-0800'>{</span>
|
|
<a id='x1-38055r26'></a><span class='ecrm-0500'>26</span><span class='ectt-0800'> sscanf(buf, </span><span id='textcolor937'><span class='ectt-0800'>"%du"</span></span><span class='ectt-0800'>, &myvariable);</span>
|
|
<a id='x1-38057r27'></a><span class='ecrm-0500'>27</span><span class='ectt-0800'> </span><span id='textcolor938'><span class='ectt-0800'>return</span></span><span class='ectt-0800'> count;</span>
|
|
<a id='x1-38059r28'></a><span class='ecrm-0500'>28</span><span class='ectt-0800'>}</span>
|
|
<a id='x1-38061r29'></a><span class='ecrm-0500'>29</span>
|
|
<a id='x1-38063r30'></a><span class='ecrm-0500'>30</span><span id='textcolor939'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor940'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> kobj_attribute myvariable_attribute =</span>
|
|
<a id='x1-38065r31'></a><span class='ecrm-0500'>31</span><span class='ectt-0800'> __ATTR(myvariable, 0660, myvariable_show, (</span><span id='textcolor941'><span class='ectt-0800'>void</span></span><span class='ectt-0800'> *)myvariable_store);</span>
|
|
<a id='x1-38067r32'></a><span class='ecrm-0500'>32</span>
|
|
<a id='x1-38069r33'></a><span class='ecrm-0500'>33</span><span id='textcolor942'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor943'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> __init mymodule_init(</span><span id='textcolor944'><span class='ectt-0800'>void</span></span><span class='ectt-0800'>)</span>
|
|
<a id='x1-38071r34'></a><span class='ecrm-0500'>34</span><span class='ectt-0800'>{</span>
|
|
<a id='x1-38073r35'></a><span class='ecrm-0500'>35</span><span class='ectt-0800'> </span><span id='textcolor945'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> error = 0;</span>
|
|
<a id='x1-38075r36'></a><span class='ecrm-0500'>36</span>
|
|
<a id='x1-38077r37'></a><span class='ecrm-0500'>37</span><span class='ectt-0800'> pr_info(</span><span id='textcolor946'><span class='ectt-0800'>"mymodule: initialised</span></span><span id='textcolor947'><span class='ectt-0800'>\n</span></span><span id='textcolor948'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>);</span>
|
|
<a id='x1-38079r38'></a><span class='ecrm-0500'>38</span>
|
|
<a id='x1-38081r39'></a><span class='ecrm-0500'>39</span><span class='ectt-0800'> mymodule = kobject_create_and_add(</span><span id='textcolor949'><span class='ectt-0800'>"mymodule"</span></span><span class='ectt-0800'>, kernel_kobj);</span>
|
|
<a id='x1-38083r40'></a><span class='ecrm-0500'>40</span><span class='ectt-0800'> </span><span id='textcolor950'><span class='ectt-0800'>if</span></span><span class='ectt-0800'> (!mymodule)</span>
|
|
<a id='x1-38085r41'></a><span class='ecrm-0500'>41</span><span class='ectt-0800'> </span><span id='textcolor951'><span class='ectt-0800'>return</span></span><span class='ectt-0800'> -ENOMEM;</span>
|
|
<a id='x1-38087r42'></a><span class='ecrm-0500'>42</span>
|
|
<a id='x1-38089r43'></a><span class='ecrm-0500'>43</span><span class='ectt-0800'> error = sysfs_create_file(mymodule, &myvariable_attribute.attr);</span>
|
|
<a id='x1-38091r44'></a><span class='ecrm-0500'>44</span><span class='ectt-0800'> </span><span id='textcolor952'><span class='ectt-0800'>if</span></span><span class='ectt-0800'> (error) {</span>
|
|
<a id='x1-38093r45'></a><span class='ecrm-0500'>45</span><span class='ectt-0800'> pr_info(</span><span id='textcolor953'><span class='ectt-0800'>"failed to create the myvariable file "</span></span>
|
|
<a id='x1-38095r46'></a><span class='ecrm-0500'>46</span><span class='ectt-0800'> </span><span id='textcolor954'><span class='ectt-0800'>"in /sys/kernel/mymodule</span></span><span id='textcolor955'><span class='ectt-0800'>\n</span></span><span id='textcolor956'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>);</span>
|
|
<a id='x1-38097r47'></a><span class='ecrm-0500'>47</span><span class='ectt-0800'> }</span>
|
|
<a id='x1-38099r48'></a><span class='ecrm-0500'>48</span>
|
|
<a id='x1-38101r49'></a><span class='ecrm-0500'>49</span><span class='ectt-0800'> </span><span id='textcolor957'><span class='ectt-0800'>return</span></span><span class='ectt-0800'> error;</span>
|
|
<a id='x1-38103r50'></a><span class='ecrm-0500'>50</span><span class='ectt-0800'>}</span>
|
|
<a id='x1-38105r51'></a><span class='ecrm-0500'>51</span>
|
|
<a id='x1-38107r52'></a><span class='ecrm-0500'>52</span><span id='textcolor958'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor959'><span class='ectt-0800'>void</span></span><span class='ectt-0800'> __exit mymodule_exit(</span><span id='textcolor960'><span class='ectt-0800'>void</span></span><span class='ectt-0800'>)</span>
|
|
<a id='x1-38109r53'></a><span class='ecrm-0500'>53</span><span class='ectt-0800'>{</span>
|
|
<a id='x1-38111r54'></a><span class='ecrm-0500'>54</span><span class='ectt-0800'> pr_info(</span><span id='textcolor961'><span class='ectt-0800'>"mymodule: Exit success</span></span><span id='textcolor962'><span class='ectt-0800'>\n</span></span><span id='textcolor963'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>);</span>
|
|
<a id='x1-38113r55'></a><span class='ecrm-0500'>55</span><span class='ectt-0800'> kobject_put(mymodule);</span>
|
|
<a id='x1-38115r56'></a><span class='ecrm-0500'>56</span><span class='ectt-0800'>}</span>
|
|
<a id='x1-38117r57'></a><span class='ecrm-0500'>57</span>
|
|
<a id='x1-38119r58'></a><span class='ecrm-0500'>58</span><span class='ectt-0800'>module_init(mymodule_init);</span>
|
|
<a id='x1-38121r59'></a><span class='ecrm-0500'>59</span><span class='ectt-0800'>module_exit(mymodule_exit);</span>
|
|
<a id='x1-38123r60'></a><span class='ecrm-0500'>60</span>
|
|
<a id='x1-38125r61'></a><span class='ecrm-0500'>61</span><span class='ectt-0800'>MODULE_LICENSE(</span><span id='textcolor964'><span class='ectt-0800'>"GPL"</span></span><span class='ectt-0800'>);</span></pre>
|
|
<!-- l. 1108 --><p class='indent'> Make and install the module:
|
|
</p><!-- l. 1 --><p class='indent'>
|
|
</p>
|
|
<pre class='fancyvrb' id='fancyvrb44'><a id='x1-38129r1'></a><span class='ecrm-0500'>1</span><span class='ectt-1000'>make</span>
|
|
<a id='x1-38131r2'></a><span class='ecrm-0500'>2</span><span class='ectt-1000'>sudo insmod hello-sysfs.ko</span></pre>
|
|
|
|
|
|
|
|
<!-- l. 1115 --><p class='indent'> Check that it exists:
|
|
</p><!-- l. 1 --><p class='indent'>
|
|
</p>
|
|
<pre class='fancyvrb' id='fancyvrb45'><a id='x1-38134r1'></a><span class='ecrm-0500'>1</span><span class='ectt-1000'>sudo lsmod | grep hello_sysfs</span></pre>
|
|
<!-- l. 1121 --><p class='indent'> What is the current value of <code> <span class='ectt-1000'>myvariable</span>
|
|
</code> ?
|
|
</p><!-- l. 1 --><p class='indent'>
|
|
</p>
|
|
<pre class='fancyvrb' id='fancyvrb46'><a id='x1-38138r1'></a><span class='ecrm-0500'>1</span><span class='ectt-1000'>cat /sys/kernel/mymodule/myvariable</span></pre>
|
|
<!-- l. 1127 --><p class='indent'> Set the value of <code> <span class='ectt-1000'>myvariable</span>
|
|
</code> and check that it changed.
|
|
</p><!-- l. 1 --><p class='indent'>
|
|
</p>
|
|
<pre class='fancyvrb' id='fancyvrb47'><a id='x1-38143r1'></a><span class='ecrm-0500'>1</span><span class='ectt-1000'>echo </span><span id='textcolor965'><span class='ectt-1000'>"32"</span></span><span class='ectt-1000'> > /sys/kernel/mymodule/myvariable</span>
|
|
<a id='x1-38145r2'></a><span class='ecrm-0500'>2</span><span class='ectt-1000'>cat /sys/kernel/mymodule/myvariable</span></pre>
|
|
<!-- l. 1134 --><p class='indent'> Finally, remove the test module:
|
|
</p><!-- l. 1 --><p class='indent'>
|
|
</p>
|
|
<pre class='fancyvrb' id='fancyvrb48'><a id='x1-38148r1'></a><span class='ecrm-0500'>1</span><span class='ectt-1000'>sudo rmmod hello_sysfs</span></pre>
|
|
<!-- l. 1140 --><p class='noindent'>
|
|
</p>
|
|
<h3 class='sectionHead' id='talking-to-device-files'><span class='titlemark'>9 </span> <a id='x1-390009'></a>Talking To Device Files</h3>
|
|
<!-- l. 1142 --><p class='noindent'>Device files are supposed to represent physical devices. Most physical devices are
|
|
used for output as well as input, so there has to be some mechanism for
|
|
device drivers in the kernel to get the output to send to the device from
|
|
processes. This is done by opening the device file for output and writing to it,
|
|
just like writing to a file. In the following example, this is implemented by
|
|
<code> <span class='ectt-1000'>device_write</span>
|
|
</code>.
|
|
</p><!-- l. 1147 --><p class='indent'> This is not always enough. Imagine you had a serial port connected to a modem
|
|
(even if you have an internal modem, it is still implemented from the CPU’s
|
|
perspective as a serial port connected to a modem, so you don’t have to tax
|
|
your imagination too hard). The natural thing to do would be to use the
|
|
device file to write things to the modem (either modem commands or data to
|
|
be sent through the phone line) and read things from the modem (either
|
|
responses for commands or the data received through the phone line). However,
|
|
this leaves open the question of what to do when you need to talk to the
|
|
serial port itself, for example to configure the rate at which data is sent and
|
|
received.
|
|
|
|
|
|
|
|
</p><!-- l. 1152 --><p class='indent'> The answer in Unix is to use a special function called
|
|
<code> <span class='ectt-1000'>ioctl</span>
|
|
</code> (short for Input Output ConTroL). Every device can have its own
|
|
<code> <span class='ectt-1000'>ioctl</span>
|
|
</code> commands, which can be read ioctl’s (to send information from a process to the
|
|
kernel), write ioctl’s (to return information to a process), both or neither. Notice
|
|
here the roles of read and write are reversed again, so in ioctl’s read is to
|
|
send information to the kernel and write is to receive information from the
|
|
kernel.
|
|
</p><!-- l. 1156 --><p class='indent'> The ioctl function is called with three parameters: the file descriptor of the
|
|
appropriate device file, the ioctl number, and a parameter, which is of type
|
|
long so you can use a cast to use it to pass anything. You will not be able
|
|
to pass a structure this way, but you will be able to pass a pointer to the
|
|
structure.
|
|
</p><!-- l. 1159 --><p class='indent'> The ioctl number encodes the major device number, the type of the ioctl, the
|
|
command, and the type of the parameter. This ioctl number is usually created by a macro
|
|
call (<code> <span class='ectt-1000'>_IO</span>
|
|
</code>, <code> <span class='ectt-1000'>_IOR</span>
|
|
</code>, <code> <span class='ectt-1000'>_IOW</span>
|
|
</code> or <code> <span class='ectt-1000'>_IOWR</span>
|
|
</code> — depending on the type) in a header file. This header file should then be
|
|
included both by the programs which will use ioctl (so they can generate the
|
|
appropriate ioctl’s) and by the kernel module (so it can understand it). In the
|
|
example below, the header file is chardev.h and the program which uses it is
|
|
ioctl.c.
|
|
</p><!-- l. 1164 --><p class='indent'> If you want to use ioctls in your own kernel modules, it is best to receive an
|
|
official ioctl assignment, so if you accidentally get somebody else’s ioctls, or if they
|
|
get yours, you’ll know something is wrong. For more information, consult the kernel
|
|
source tree at <a href='https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/tree/Documentation/userspace-api/ioctl/ioctl-number.rst'>Documentation/userspace-api/ioctl/ioctl-number.rst</a>.
|
|
</p><!-- l. 1167 --><p class='indent'> Also, we need to be careful that concurrent access to the shared resources will
|
|
lead to the race condition. The solution is using atomic Compare-And-Swap (CAS),
|
|
which we mentioned at <a href='#chardevc'>6.5<!-- tex4ht:ref: sec:chardev_c --></a> section, to enforce the exclusive access.
|
|
</p><!-- l. 1 --><p class='indent'>
|
|
</p>
|
|
<pre class='fancyvrb' id='fancyvrb49'><a id='x1-39009r1'></a><span class='ecrm-0500'>1</span><span id='textcolor966'><span class='ectt-0800'>/*</span></span>
|
|
<a id='x1-39011r2'></a><span class='ecrm-0500'>2</span><span id='textcolor967'><span class='ectt-0800'> * chardev2.c - Create an input/output character device</span></span>
|
|
<a id='x1-39013r3'></a><span class='ecrm-0500'>3</span><span id='textcolor968'><span class='ectt-0800'> */</span></span>
|
|
<a id='x1-39015r4'></a><span class='ecrm-0500'>4</span>
|
|
<a id='x1-39017r5'></a><span class='ecrm-0500'>5</span><span id='textcolor969'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor970'><span class='ectt-0800'><linux/cdev.h></span></span>
|
|
<a id='x1-39019r6'></a><span class='ecrm-0500'>6</span><span id='textcolor971'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor972'><span class='ectt-0800'><linux/delay.h></span></span>
|
|
<a id='x1-39021r7'></a><span class='ecrm-0500'>7</span><span id='textcolor973'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor974'><span class='ectt-0800'><linux/device.h></span></span>
|
|
<a id='x1-39023r8'></a><span class='ecrm-0500'>8</span><span id='textcolor975'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor976'><span class='ectt-0800'><linux/fs.h></span></span>
|
|
<a id='x1-39025r9'></a><span class='ecrm-0500'>9</span><span id='textcolor977'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor978'><span class='ectt-0800'><linux/init.h></span></span>
|
|
<a id='x1-39027r10'></a><span class='ecrm-0500'>10</span><span id='textcolor979'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor980'><span class='ectt-0800'><linux/irq.h></span></span>
|
|
<a id='x1-39029r11'></a><span class='ecrm-0500'>11</span><span id='textcolor981'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor982'><span class='ectt-0800'><linux/kernel.h> /* We are doing kernel work */</span></span>
|
|
<a id='x1-39031r12'></a><span class='ecrm-0500'>12</span><span id='textcolor983'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor984'><span class='ectt-0800'><linux/module.h> /* Specifically, a module */</span></span>
|
|
<a id='x1-39033r13'></a><span class='ecrm-0500'>13</span><span id='textcolor985'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor986'><span class='ectt-0800'><linux/poll.h></span></span>
|
|
<a id='x1-39035r14'></a><span class='ecrm-0500'>14</span>
|
|
<a id='x1-39037r15'></a><span class='ecrm-0500'>15</span><span id='textcolor987'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor988'><span class='ectt-0800'>"chardev.h"</span></span>
|
|
<a id='x1-39039r16'></a><span class='ecrm-0500'>16</span><span id='textcolor989'><span class='ectt-0800'>#define SUCCESS 0</span></span>
|
|
<a id='x1-39041r17'></a><span class='ecrm-0500'>17</span><span id='textcolor990'><span class='ectt-0800'>#define DEVICE_NAME "char_dev"</span></span>
|
|
<a id='x1-39043r18'></a><span class='ecrm-0500'>18</span><span id='textcolor991'><span class='ectt-0800'>#define BUF_LEN 80</span></span>
|
|
<a id='x1-39045r19'></a><span class='ecrm-0500'>19</span>
|
|
<a id='x1-39047r20'></a><span class='ecrm-0500'>20</span><span id='textcolor992'><span class='ectt-0800'>/* Is the device open right now? Used to prevent concurrent access into</span></span>
|
|
<a id='x1-39049r21'></a><span class='ecrm-0500'>21</span><span id='textcolor993'><span class='ectt-0800'> * the same device</span></span>
|
|
<a id='x1-39051r22'></a><span class='ecrm-0500'>22</span><span id='textcolor994'><span class='ectt-0800'> */</span></span>
|
|
<a id='x1-39053r23'></a><span class='ecrm-0500'>23</span><span id='textcolor995'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> atomic_t already_open = ATOMIC_INIT(0);</span>
|
|
<a id='x1-39055r24'></a><span class='ecrm-0500'>24</span>
|
|
<a id='x1-39057r25'></a><span class='ecrm-0500'>25</span><span id='textcolor996'><span class='ectt-0800'>/* The message the device will give when asked */</span></span>
|
|
<a id='x1-39059r26'></a><span class='ecrm-0500'>26</span><span id='textcolor997'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor998'><span class='ectt-0800'>char</span></span><span class='ectt-0800'> message[BUF_LEN];</span>
|
|
<a id='x1-39061r27'></a><span class='ecrm-0500'>27</span>
|
|
<a id='x1-39063r28'></a><span class='ecrm-0500'>28</span><span id='textcolor999'><span class='ectt-0800'>/* How far did the process reading the message get? Useful if the message</span></span>
|
|
<a id='x1-39065r29'></a><span class='ecrm-0500'>29</span><span id='textcolor1000'><span class='ectt-0800'> * is larger than the size of the buffer we get to fill in device_read.</span></span>
|
|
<a id='x1-39067r30'></a><span class='ecrm-0500'>30</span><span id='textcolor1001'><span class='ectt-0800'> */</span></span>
|
|
<a id='x1-39069r31'></a><span class='ecrm-0500'>31</span><span id='textcolor1002'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor1003'><span class='ectt-0800'>char</span></span><span class='ectt-0800'> *message_ptr;</span>
|
|
<a id='x1-39071r32'></a><span class='ecrm-0500'>32</span>
|
|
<a id='x1-39073r33'></a><span class='ecrm-0500'>33</span><span id='textcolor1004'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor1005'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> class *cls;</span>
|
|
<a id='x1-39075r34'></a><span class='ecrm-0500'>34</span>
|
|
<a id='x1-39077r35'></a><span class='ecrm-0500'>35</span><span id='textcolor1006'><span class='ectt-0800'>/* This is called whenever a process attempts to open the device file */</span></span>
|
|
<a id='x1-39079r36'></a><span class='ecrm-0500'>36</span><span id='textcolor1007'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor1008'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> device_open(</span><span id='textcolor1009'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> inode *inode, </span><span id='textcolor1010'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> file *file)</span>
|
|
<a id='x1-39081r37'></a><span class='ecrm-0500'>37</span><span class='ectt-0800'>{</span>
|
|
<a id='x1-39083r38'></a><span class='ecrm-0500'>38</span><span class='ectt-0800'> pr_info(</span><span id='textcolor1011'><span class='ectt-0800'>"device_open(%p)</span></span><span id='textcolor1012'><span class='ectt-0800'>\n</span></span><span id='textcolor1013'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>, file);</span>
|
|
<a id='x1-39085r39'></a><span class='ecrm-0500'>39</span>
|
|
<a id='x1-39087r40'></a><span class='ecrm-0500'>40</span><span class='ectt-0800'> </span><span id='textcolor1014'><span class='ectt-0800'>/* We don</span><span class='tctt-0800'>'</span><span class='ectt-0800'>t want to talk to two processes at the same time. */</span></span>
|
|
<a id='x1-39089r41'></a><span class='ecrm-0500'>41</span><span class='ectt-0800'> </span><span id='textcolor1015'><span class='ectt-0800'>if</span></span><span class='ectt-0800'> (atomic_cmpxchg(&already_open, 0, 1))</span>
|
|
<a id='x1-39091r42'></a><span class='ecrm-0500'>42</span><span class='ectt-0800'> </span><span id='textcolor1016'><span class='ectt-0800'>return</span></span><span class='ectt-0800'> -EBUSY;</span>
|
|
<a id='x1-39093r43'></a><span class='ecrm-0500'>43</span>
|
|
<a id='x1-39095r44'></a><span class='ecrm-0500'>44</span><span class='ectt-0800'> </span><span id='textcolor1017'><span class='ectt-0800'>/* Initialize the message */</span></span>
|
|
<a id='x1-39097r45'></a><span class='ecrm-0500'>45</span><span class='ectt-0800'> message_ptr = message;</span>
|
|
<a id='x1-39099r46'></a><span class='ecrm-0500'>46</span><span class='ectt-0800'> try_module_get(THIS_MODULE);</span>
|
|
<a id='x1-39101r47'></a><span class='ecrm-0500'>47</span><span class='ectt-0800'> </span><span id='textcolor1018'><span class='ectt-0800'>return</span></span><span class='ectt-0800'> SUCCESS;</span>
|
|
<a id='x1-39103r48'></a><span class='ecrm-0500'>48</span><span class='ectt-0800'>}</span>
|
|
<a id='x1-39105r49'></a><span class='ecrm-0500'>49</span>
|
|
<a id='x1-39107r50'></a><span class='ecrm-0500'>50</span><span id='textcolor1019'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor1020'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> device_release(</span><span id='textcolor1021'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> inode *inode, </span><span id='textcolor1022'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> file *file)</span>
|
|
<a id='x1-39109r51'></a><span class='ecrm-0500'>51</span><span class='ectt-0800'>{</span>
|
|
<a id='x1-39111r52'></a><span class='ecrm-0500'>52</span><span class='ectt-0800'> pr_info(</span><span id='textcolor1023'><span class='ectt-0800'>"device_release(%p,%p)</span></span><span id='textcolor1024'><span class='ectt-0800'>\n</span></span><span id='textcolor1025'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>, inode, file);</span>
|
|
<a id='x1-39113r53'></a><span class='ecrm-0500'>53</span>
|
|
<a id='x1-39115r54'></a><span class='ecrm-0500'>54</span><span class='ectt-0800'> </span><span id='textcolor1026'><span class='ectt-0800'>/* We</span><span class='tctt-0800'>'</span><span class='ectt-0800'>re now ready for our next caller */</span></span>
|
|
<a id='x1-39117r55'></a><span class='ecrm-0500'>55</span><span class='ectt-0800'> atomic_set(&already_open, 0);</span>
|
|
<a id='x1-39119r56'></a><span class='ecrm-0500'>56</span>
|
|
<a id='x1-39121r57'></a><span class='ecrm-0500'>57</span><span class='ectt-0800'> module_put(THIS_MODULE);</span>
|
|
<a id='x1-39123r58'></a><span class='ecrm-0500'>58</span><span class='ectt-0800'> </span><span id='textcolor1027'><span class='ectt-0800'>return</span></span><span class='ectt-0800'> SUCCESS;</span>
|
|
<a id='x1-39125r59'></a><span class='ecrm-0500'>59</span><span class='ectt-0800'>}</span>
|
|
<a id='x1-39127r60'></a><span class='ecrm-0500'>60</span>
|
|
<a id='x1-39129r61'></a><span class='ecrm-0500'>61</span><span id='textcolor1028'><span class='ectt-0800'>/* This function is called whenever a process which has already opened the</span></span>
|
|
<a id='x1-39131r62'></a><span class='ecrm-0500'>62</span><span id='textcolor1029'><span class='ectt-0800'> * device file attempts to read from it.</span></span>
|
|
<a id='x1-39133r63'></a><span class='ecrm-0500'>63</span><span id='textcolor1030'><span class='ectt-0800'> */</span></span>
|
|
<a id='x1-39135r64'></a><span class='ecrm-0500'>64</span><span id='textcolor1031'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor1032'><span class='ectt-0800'>ssize_t</span></span><span class='ectt-0800'> device_read(</span><span id='textcolor1033'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> file *file, </span><span id='textcolor1034'><span class='ectt-0800'>/* see include/linux/fs.h */</span></span>
|
|
<a id='x1-39137r65'></a><span class='ecrm-0500'>65</span><span class='ectt-0800'> </span><span id='textcolor1035'><span class='ectt-0800'>char</span></span><span class='ectt-0800'> __user *buffer, </span><span id='textcolor1036'><span class='ectt-0800'>/* buffer to be filled */</span></span>
|
|
<a id='x1-39139r66'></a><span class='ecrm-0500'>66</span><span class='ectt-0800'> </span><span id='textcolor1037'><span class='ectt-0800'>size_t</span></span><span class='ectt-0800'> length, </span><span id='textcolor1038'><span class='ectt-0800'>/* length of the buffer */</span></span>
|
|
<a id='x1-39141r67'></a><span class='ecrm-0500'>67</span><span class='ectt-0800'> loff_t *offset)</span>
|
|
<a id='x1-39143r68'></a><span class='ecrm-0500'>68</span><span class='ectt-0800'>{</span>
|
|
<a id='x1-39145r69'></a><span class='ecrm-0500'>69</span><span class='ectt-0800'> </span><span id='textcolor1039'><span class='ectt-0800'>/* Number of bytes actually written to the buffer */</span></span>
|
|
<a id='x1-39147r70'></a><span class='ecrm-0500'>70</span><span class='ectt-0800'> </span><span id='textcolor1040'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> bytes_read = 0;</span>
|
|
<a id='x1-39149r71'></a><span class='ecrm-0500'>71</span>
|
|
<a id='x1-39151r72'></a><span class='ecrm-0500'>72</span><span class='ectt-0800'> pr_info(</span><span id='textcolor1041'><span class='ectt-0800'>"device_read(%p,%p,%ld)</span></span><span id='textcolor1042'><span class='ectt-0800'>\n</span></span><span id='textcolor1043'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>, file, buffer, length);</span>
|
|
<a id='x1-39153r73'></a><span class='ecrm-0500'>73</span>
|
|
<a id='x1-39155r74'></a><span class='ecrm-0500'>74</span><span class='ectt-0800'> </span><span id='textcolor1044'><span class='ectt-0800'>/* If at the end of message, return 0 (which signifies end of file). */</span></span>
|
|
<a id='x1-39157r75'></a><span class='ecrm-0500'>75</span><span class='ectt-0800'> </span><span id='textcolor1045'><span class='ectt-0800'>if</span></span><span class='ectt-0800'> (*message_ptr == 0)</span>
|
|
<a id='x1-39159r76'></a><span class='ecrm-0500'>76</span><span class='ectt-0800'> </span><span id='textcolor1046'><span class='ectt-0800'>return</span></span><span class='ectt-0800'> 0;</span>
|
|
<a id='x1-39161r77'></a><span class='ecrm-0500'>77</span>
|
|
<a id='x1-39163r78'></a><span class='ecrm-0500'>78</span><span class='ectt-0800'> </span><span id='textcolor1047'><span class='ectt-0800'>/* Actually put the data into the buffer */</span></span>
|
|
<a id='x1-39165r79'></a><span class='ecrm-0500'>79</span><span class='ectt-0800'> </span><span id='textcolor1048'><span class='ectt-0800'>while</span></span><span class='ectt-0800'> (length && *message_ptr) {</span>
|
|
<a id='x1-39167r80'></a><span class='ecrm-0500'>80</span><span class='ectt-0800'> </span><span id='textcolor1049'><span class='ectt-0800'>/* Because the buffer is in the user data segment, not the kernel</span></span>
|
|
<a id='x1-39169r81'></a><span class='ecrm-0500'>81</span><span id='textcolor1050'><span class='ectt-0800'> * data segment, assignment would not work. Instead, we have to</span></span>
|
|
<a id='x1-39171r82'></a><span class='ecrm-0500'>82</span><span id='textcolor1051'><span class='ectt-0800'> * use put_user which copies data from the kernel data segment to</span></span>
|
|
<a id='x1-39173r83'></a><span class='ecrm-0500'>83</span><span id='textcolor1052'><span class='ectt-0800'> * the user data segment.</span></span>
|
|
<a id='x1-39175r84'></a><span class='ecrm-0500'>84</span><span id='textcolor1053'><span class='ectt-0800'> */</span></span>
|
|
<a id='x1-39177r85'></a><span class='ecrm-0500'>85</span><span class='ectt-0800'> put_user(*(message_ptr++), buffer++);</span>
|
|
<a id='x1-39179r86'></a><span class='ecrm-0500'>86</span><span class='ectt-0800'> length--;</span>
|
|
<a id='x1-39181r87'></a><span class='ecrm-0500'>87</span><span class='ectt-0800'> bytes_read++;</span>
|
|
<a id='x1-39183r88'></a><span class='ecrm-0500'>88</span><span class='ectt-0800'> }</span>
|
|
<a id='x1-39185r89'></a><span class='ecrm-0500'>89</span>
|
|
<a id='x1-39187r90'></a><span class='ecrm-0500'>90</span><span class='ectt-0800'> pr_info(</span><span id='textcolor1054'><span class='ectt-0800'>"Read %d bytes, %ld left</span></span><span id='textcolor1055'><span class='ectt-0800'>\n</span></span><span id='textcolor1056'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>, bytes_read, length);</span>
|
|
<a id='x1-39189r91'></a><span class='ecrm-0500'>91</span>
|
|
<a id='x1-39191r92'></a><span class='ecrm-0500'>92</span><span class='ectt-0800'> </span><span id='textcolor1057'><span class='ectt-0800'>/* Read functions are supposed to return the number of bytes actually</span></span>
|
|
<a id='x1-39193r93'></a><span class='ecrm-0500'>93</span><span id='textcolor1058'><span class='ectt-0800'> * inserted into the buffer.</span></span>
|
|
<a id='x1-39195r94'></a><span class='ecrm-0500'>94</span><span id='textcolor1059'><span class='ectt-0800'> */</span></span>
|
|
<a id='x1-39197r95'></a><span class='ecrm-0500'>95</span><span class='ectt-0800'> </span><span id='textcolor1060'><span class='ectt-0800'>return</span></span><span class='ectt-0800'> bytes_read;</span>
|
|
<a id='x1-39199r96'></a><span class='ecrm-0500'>96</span><span class='ectt-0800'>}</span>
|
|
<a id='x1-39201r97'></a><span class='ecrm-0500'>97</span>
|
|
<a id='x1-39203r98'></a><span class='ecrm-0500'>98</span><span id='textcolor1061'><span class='ectt-0800'>/* called when somebody tries to write into our device file. */</span></span>
|
|
<a id='x1-39205r99'></a><span class='ecrm-0500'>99</span><span id='textcolor1062'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor1063'><span class='ectt-0800'>ssize_t</span></span><span class='ectt-0800'> device_write(</span><span id='textcolor1064'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> file *file, </span><span id='textcolor1065'><span class='ectt-0800'>const</span></span><span class='ectt-0800'> </span><span id='textcolor1066'><span class='ectt-0800'>char</span></span><span class='ectt-0800'> __user *buffer,</span>
|
|
<a id='x1-39207r100'></a><span class='ecrm-0500'>100</span><span class='ectt-0800'> </span><span id='textcolor1067'><span class='ectt-0800'>size_t</span></span><span class='ectt-0800'> length, loff_t *offset)</span>
|
|
<a id='x1-39209r101'></a><span class='ecrm-0500'>101</span><span class='ectt-0800'>{</span>
|
|
<a id='x1-39211r102'></a><span class='ecrm-0500'>102</span><span class='ectt-0800'> </span><span id='textcolor1068'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> i;</span>
|
|
<a id='x1-39213r103'></a><span class='ecrm-0500'>103</span>
|
|
<a id='x1-39215r104'></a><span class='ecrm-0500'>104</span><span class='ectt-0800'> pr_info(</span><span id='textcolor1069'><span class='ectt-0800'>"device_write(%p,%s,%ld)"</span></span><span class='ectt-0800'>, file, buffer, length);</span>
|
|
<a id='x1-39217r105'></a><span class='ecrm-0500'>105</span>
|
|
<a id='x1-39219r106'></a><span class='ecrm-0500'>106</span><span class='ectt-0800'> </span><span id='textcolor1070'><span class='ectt-0800'>for</span></span><span class='ectt-0800'> (i = 0; i < length && i < BUF_LEN; i++)</span>
|
|
<a id='x1-39221r107'></a><span class='ecrm-0500'>107</span><span class='ectt-0800'> get_user(message[i], buffer + i);</span>
|
|
<a id='x1-39223r108'></a><span class='ecrm-0500'>108</span>
|
|
<a id='x1-39225r109'></a><span class='ecrm-0500'>109</span><span class='ectt-0800'> message_ptr = message;</span>
|
|
<a id='x1-39227r110'></a><span class='ecrm-0500'>110</span>
|
|
<a id='x1-39229r111'></a><span class='ecrm-0500'>111</span><span class='ectt-0800'> </span><span id='textcolor1071'><span class='ectt-0800'>/* Again, return the number of input characters used. */</span></span>
|
|
<a id='x1-39231r112'></a><span class='ecrm-0500'>112</span><span class='ectt-0800'> </span><span id='textcolor1072'><span class='ectt-0800'>return</span></span><span class='ectt-0800'> i;</span>
|
|
<a id='x1-39233r113'></a><span class='ecrm-0500'>113</span><span class='ectt-0800'>}</span>
|
|
<a id='x1-39235r114'></a><span class='ecrm-0500'>114</span>
|
|
<a id='x1-39237r115'></a><span class='ecrm-0500'>115</span><span id='textcolor1073'><span class='ectt-0800'>/* This function is called whenever a process tries to do an ioctl on our</span></span>
|
|
<a id='x1-39239r116'></a><span class='ecrm-0500'>116</span><span id='textcolor1074'><span class='ectt-0800'> * device file. We get two extra parameters (additional to the inode and file</span></span>
|
|
<a id='x1-39241r117'></a><span class='ecrm-0500'>117</span><span id='textcolor1075'><span class='ectt-0800'> * structures, which all device functions get): the number of the ioctl called</span></span>
|
|
<a id='x1-39243r118'></a><span class='ecrm-0500'>118</span><span id='textcolor1076'><span class='ectt-0800'> * and the parameter given to the ioctl function.</span></span>
|
|
<a id='x1-39245r119'></a><span class='ecrm-0500'>119</span><span id='textcolor1077'><span class='ectt-0800'> *</span></span>
|
|
<a id='x1-39247r120'></a><span class='ecrm-0500'>120</span><span id='textcolor1078'><span class='ectt-0800'> * If the ioctl is write or read/write (meaning output is returned to the</span></span>
|
|
<a id='x1-39249r121'></a><span class='ecrm-0500'>121</span><span id='textcolor1079'><span class='ectt-0800'> * calling process), the ioctl call returns the output of this function.</span></span>
|
|
<a id='x1-39251r122'></a><span class='ecrm-0500'>122</span><span id='textcolor1080'><span class='ectt-0800'> */</span></span>
|
|
<a id='x1-39253r123'></a><span class='ecrm-0500'>123</span><span id='textcolor1081'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor1082'><span class='ectt-0800'>long</span></span>
|
|
<a id='x1-39255r124'></a><span class='ecrm-0500'>124</span><span class='ectt-0800'>device_ioctl(</span><span id='textcolor1083'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> file *file, </span><span id='textcolor1084'><span class='ectt-0800'>/* ditto */</span></span>
|
|
<a id='x1-39257r125'></a><span class='ecrm-0500'>125</span><span class='ectt-0800'> </span><span id='textcolor1085'><span class='ectt-0800'>unsigned</span></span><span class='ectt-0800'> </span><span id='textcolor1086'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> ioctl_num, </span><span id='textcolor1087'><span class='ectt-0800'>/* number and param for ioctl */</span></span>
|
|
<a id='x1-39259r126'></a><span class='ecrm-0500'>126</span><span class='ectt-0800'> </span><span id='textcolor1088'><span class='ectt-0800'>unsigned</span></span><span class='ectt-0800'> </span><span id='textcolor1089'><span class='ectt-0800'>long</span></span><span class='ectt-0800'> ioctl_param)</span>
|
|
<a id='x1-39261r127'></a><span class='ecrm-0500'>127</span><span class='ectt-0800'>{</span>
|
|
<a id='x1-39263r128'></a><span class='ecrm-0500'>128</span><span class='ectt-0800'> </span><span id='textcolor1090'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> i;</span>
|
|
<a id='x1-39265r129'></a><span class='ecrm-0500'>129</span><span class='ectt-0800'> </span><span id='textcolor1091'><span class='ectt-0800'>char</span></span><span class='ectt-0800'> *temp;</span>
|
|
<a id='x1-39267r130'></a><span class='ecrm-0500'>130</span><span class='ectt-0800'> </span><span id='textcolor1092'><span class='ectt-0800'>char</span></span><span class='ectt-0800'> ch;</span>
|
|
<a id='x1-39269r131'></a><span class='ecrm-0500'>131</span>
|
|
<a id='x1-39271r132'></a><span class='ecrm-0500'>132</span><span class='ectt-0800'> </span><span id='textcolor1093'><span class='ectt-0800'>/* Switch according to the ioctl called */</span></span>
|
|
<a id='x1-39273r133'></a><span class='ecrm-0500'>133</span><span class='ectt-0800'> </span><span id='textcolor1094'><span class='ectt-0800'>switch</span></span><span class='ectt-0800'> (ioctl_num) {</span>
|
|
<a id='x1-39275r134'></a><span class='ecrm-0500'>134</span><span class='ectt-0800'> </span><span id='textcolor1095'><span class='ectt-0800'>case</span></span><span class='ectt-0800'> IOCTL_SET_MSG:</span>
|
|
<a id='x1-39277r135'></a><span class='ecrm-0500'>135</span><span class='ectt-0800'> </span><span id='textcolor1096'><span class='ectt-0800'>/* Receive a pointer to a message (in user space) and set that to</span></span>
|
|
<a id='x1-39279r136'></a><span class='ecrm-0500'>136</span><span id='textcolor1097'><span class='ectt-0800'> * be the device</span><span class='tctt-0800'>'</span><span class='ectt-0800'>s message. Get the parameter given to ioctl by</span></span>
|
|
<a id='x1-39281r137'></a><span class='ecrm-0500'>137</span><span id='textcolor1098'><span class='ectt-0800'> * the process.</span></span>
|
|
<a id='x1-39283r138'></a><span class='ecrm-0500'>138</span><span id='textcolor1099'><span class='ectt-0800'> */</span></span>
|
|
<a id='x1-39285r139'></a><span class='ecrm-0500'>139</span><span class='ectt-0800'> temp = (</span><span id='textcolor1100'><span class='ectt-0800'>char</span></span><span class='ectt-0800'> *)ioctl_param;</span>
|
|
<a id='x1-39287r140'></a><span class='ecrm-0500'>140</span>
|
|
<a id='x1-39289r141'></a><span class='ecrm-0500'>141</span><span class='ectt-0800'> </span><span id='textcolor1101'><span class='ectt-0800'>/* Find the length of the message */</span></span>
|
|
<a id='x1-39291r142'></a><span class='ecrm-0500'>142</span><span class='ectt-0800'> get_user(ch, (</span><span id='textcolor1102'><span class='ectt-0800'>char</span></span><span class='ectt-0800'> __user *)temp);</span>
|
|
<a id='x1-39293r143'></a><span class='ecrm-0500'>143</span><span class='ectt-0800'> </span><span id='textcolor1103'><span class='ectt-0800'>for</span></span><span class='ectt-0800'> (i = 0; ch && i < BUF_LEN; i++, temp++)</span>
|
|
<a id='x1-39295r144'></a><span class='ecrm-0500'>144</span><span class='ectt-0800'> get_user(ch, (</span><span id='textcolor1104'><span class='ectt-0800'>char</span></span><span class='ectt-0800'> __user *)temp);</span>
|
|
<a id='x1-39297r145'></a><span class='ecrm-0500'>145</span>
|
|
<a id='x1-39299r146'></a><span class='ecrm-0500'>146</span><span class='ectt-0800'> device_write(file, (</span><span id='textcolor1105'><span class='ectt-0800'>char</span></span><span class='ectt-0800'> __user *)ioctl_param, i, NULL);</span>
|
|
<a id='x1-39301r147'></a><span class='ecrm-0500'>147</span><span class='ectt-0800'> </span><span id='textcolor1106'><span class='ectt-0800'>break</span></span><span class='ectt-0800'>;</span>
|
|
<a id='x1-39303r148'></a><span class='ecrm-0500'>148</span>
|
|
<a id='x1-39305r149'></a><span class='ecrm-0500'>149</span><span class='ectt-0800'> </span><span id='textcolor1107'><span class='ectt-0800'>case</span></span><span class='ectt-0800'> IOCTL_GET_MSG:</span>
|
|
<a id='x1-39307r150'></a><span class='ecrm-0500'>150</span><span class='ectt-0800'> </span><span id='textcolor1108'><span class='ectt-0800'>/* Give the current message to the calling process - the parameter</span></span>
|
|
<a id='x1-39309r151'></a><span class='ecrm-0500'>151</span><span id='textcolor1109'><span class='ectt-0800'> * we got is a pointer, fill it.</span></span>
|
|
<a id='x1-39311r152'></a><span class='ecrm-0500'>152</span><span id='textcolor1110'><span class='ectt-0800'> */</span></span>
|
|
<a id='x1-39313r153'></a><span class='ecrm-0500'>153</span><span class='ectt-0800'> i = device_read(file, (</span><span id='textcolor1111'><span class='ectt-0800'>char</span></span><span class='ectt-0800'> __user *)ioctl_param, 99, NULL);</span>
|
|
<a id='x1-39315r154'></a><span class='ecrm-0500'>154</span>
|
|
<a id='x1-39317r155'></a><span class='ecrm-0500'>155</span><span class='ectt-0800'> </span><span id='textcolor1112'><span class='ectt-0800'>/* Put a zero at the end of the buffer, so it will be properly</span></span>
|
|
<a id='x1-39319r156'></a><span class='ecrm-0500'>156</span><span id='textcolor1113'><span class='ectt-0800'> * terminated.</span></span>
|
|
<a id='x1-39321r157'></a><span class='ecrm-0500'>157</span><span id='textcolor1114'><span class='ectt-0800'> */</span></span>
|
|
<a id='x1-39323r158'></a><span class='ecrm-0500'>158</span><span class='ectt-0800'> put_user(</span><span id='textcolor1115'><span class='tctt-0800'>'</span><span class='ectt-0800'>\0</span><span class='tctt-0800'>'</span></span><span class='ectt-0800'>, (</span><span id='textcolor1116'><span class='ectt-0800'>char</span></span><span class='ectt-0800'> __user *)ioctl_param + i);</span>
|
|
<a id='x1-39325r159'></a><span class='ecrm-0500'>159</span><span class='ectt-0800'> </span><span id='textcolor1117'><span class='ectt-0800'>break</span></span><span class='ectt-0800'>;</span>
|
|
<a id='x1-39327r160'></a><span class='ecrm-0500'>160</span>
|
|
<a id='x1-39329r161'></a><span class='ecrm-0500'>161</span><span class='ectt-0800'> </span><span id='textcolor1118'><span class='ectt-0800'>case</span></span><span class='ectt-0800'> IOCTL_GET_NTH_BYTE:</span>
|
|
<a id='x1-39331r162'></a><span class='ecrm-0500'>162</span><span class='ectt-0800'> </span><span id='textcolor1119'><span class='ectt-0800'>/* This ioctl is both input (ioctl_param) and output (the return</span></span>
|
|
<a id='x1-39333r163'></a><span class='ecrm-0500'>163</span><span id='textcolor1120'><span class='ectt-0800'> * value of this function).</span></span>
|
|
<a id='x1-39335r164'></a><span class='ecrm-0500'>164</span><span id='textcolor1121'><span class='ectt-0800'> */</span></span>
|
|
<a id='x1-39337r165'></a><span class='ecrm-0500'>165</span><span class='ectt-0800'> </span><span id='textcolor1122'><span class='ectt-0800'>return</span></span><span class='ectt-0800'> message[ioctl_param];</span>
|
|
<a id='x1-39339r166'></a><span class='ecrm-0500'>166</span><span class='ectt-0800'> </span><span id='textcolor1123'><span class='ectt-0800'>break</span></span><span class='ectt-0800'>;</span>
|
|
<a id='x1-39341r167'></a><span class='ecrm-0500'>167</span><span class='ectt-0800'> }</span>
|
|
<a id='x1-39343r168'></a><span class='ecrm-0500'>168</span>
|
|
<a id='x1-39345r169'></a><span class='ecrm-0500'>169</span><span class='ectt-0800'> </span><span id='textcolor1124'><span class='ectt-0800'>return</span></span><span class='ectt-0800'> SUCCESS;</span>
|
|
<a id='x1-39347r170'></a><span class='ecrm-0500'>170</span><span class='ectt-0800'>}</span>
|
|
<a id='x1-39349r171'></a><span class='ecrm-0500'>171</span>
|
|
<a id='x1-39351r172'></a><span class='ecrm-0500'>172</span><span id='textcolor1125'><span class='ectt-0800'>/* Module Declarations */</span></span>
|
|
<a id='x1-39353r173'></a><span class='ecrm-0500'>173</span>
|
|
<a id='x1-39355r174'></a><span class='ecrm-0500'>174</span><span id='textcolor1126'><span class='ectt-0800'>/* This structure will hold the functions to be called when a process does</span></span>
|
|
<a id='x1-39357r175'></a><span class='ecrm-0500'>175</span><span id='textcolor1127'><span class='ectt-0800'> * something to the device we created. Since a pointer to this structure</span></span>
|
|
<a id='x1-39359r176'></a><span class='ecrm-0500'>176</span><span id='textcolor1128'><span class='ectt-0800'> * is kept in the devices table, it can</span><span class='tctt-0800'>'</span><span class='ectt-0800'>t be local to init_module. NULL is</span></span>
|
|
<a id='x1-39361r177'></a><span class='ecrm-0500'>177</span><span id='textcolor1129'><span class='ectt-0800'> * for unimplemented functions.</span></span>
|
|
<a id='x1-39363r178'></a><span class='ecrm-0500'>178</span><span id='textcolor1130'><span class='ectt-0800'> */</span></span>
|
|
<a id='x1-39365r179'></a><span class='ecrm-0500'>179</span><span id='textcolor1131'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor1132'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> file_operations fops = {</span>
|
|
<a id='x1-39367r180'></a><span class='ecrm-0500'>180</span><span class='ectt-0800'> .read = device_read,</span>
|
|
<a id='x1-39369r181'></a><span class='ecrm-0500'>181</span><span class='ectt-0800'> .write = device_write,</span>
|
|
<a id='x1-39371r182'></a><span class='ecrm-0500'>182</span><span class='ectt-0800'> .unlocked_ioctl = device_ioctl,</span>
|
|
<a id='x1-39373r183'></a><span class='ecrm-0500'>183</span><span class='ectt-0800'> .open = device_open,</span>
|
|
<a id='x1-39375r184'></a><span class='ecrm-0500'>184</span><span class='ectt-0800'> .release = device_release, </span><span id='textcolor1133'><span class='ectt-0800'>/* a.k.a. close */</span></span>
|
|
<a id='x1-39377r185'></a><span class='ecrm-0500'>185</span><span class='ectt-0800'>};</span>
|
|
<a id='x1-39379r186'></a><span class='ecrm-0500'>186</span>
|
|
<a id='x1-39381r187'></a><span class='ecrm-0500'>187</span><span id='textcolor1134'><span class='ectt-0800'>/* Initialize the module - Register the character device */</span></span>
|
|
<a id='x1-39383r188'></a><span class='ecrm-0500'>188</span><span id='textcolor1135'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor1136'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> __init chardev2_init(</span><span id='textcolor1137'><span class='ectt-0800'>void</span></span><span class='ectt-0800'>)</span>
|
|
<a id='x1-39385r189'></a><span class='ecrm-0500'>189</span><span class='ectt-0800'>{</span>
|
|
<a id='x1-39387r190'></a><span class='ecrm-0500'>190</span><span class='ectt-0800'> </span><span id='textcolor1138'><span class='ectt-0800'>/* Register the character device (atleast try) */</span></span>
|
|
<a id='x1-39389r191'></a><span class='ecrm-0500'>191</span><span class='ectt-0800'> </span><span id='textcolor1139'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> ret_val = register_chrdev(MAJOR_NUM, DEVICE_NAME, &fops);</span>
|
|
<a id='x1-39391r192'></a><span class='ecrm-0500'>192</span>
|
|
<a id='x1-39393r193'></a><span class='ecrm-0500'>193</span><span class='ectt-0800'> </span><span id='textcolor1140'><span class='ectt-0800'>/* Negative values signify an error */</span></span>
|
|
<a id='x1-39395r194'></a><span class='ecrm-0500'>194</span><span class='ectt-0800'> </span><span id='textcolor1141'><span class='ectt-0800'>if</span></span><span class='ectt-0800'> (ret_val < 0) {</span>
|
|
<a id='x1-39397r195'></a><span class='ecrm-0500'>195</span><span class='ectt-0800'> pr_alert(</span><span id='textcolor1142'><span class='ectt-0800'>"%s failed with %d</span></span><span id='textcolor1143'><span class='ectt-0800'>\n</span></span><span id='textcolor1144'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>,</span>
|
|
<a id='x1-39399r196'></a><span class='ecrm-0500'>196</span><span class='ectt-0800'> </span><span id='textcolor1145'><span class='ectt-0800'>"Sorry, registering the character device "</span></span><span class='ectt-0800'>, ret_val);</span>
|
|
<a id='x1-39401r197'></a><span class='ecrm-0500'>197</span><span class='ectt-0800'> </span><span id='textcolor1146'><span class='ectt-0800'>return</span></span><span class='ectt-0800'> ret_val;</span>
|
|
<a id='x1-39403r198'></a><span class='ecrm-0500'>198</span><span class='ectt-0800'> }</span>
|
|
<a id='x1-39405r199'></a><span class='ecrm-0500'>199</span>
|
|
<a id='x1-39407r200'></a><span class='ecrm-0500'>200</span><span class='ectt-0800'> cls = class_create(THIS_MODULE, DEVICE_FILE_NAME);</span>
|
|
<a id='x1-39409r201'></a><span class='ecrm-0500'>201</span><span class='ectt-0800'> device_create(cls, NULL, MKDEV(MAJOR_NUM, 0), NULL, DEVICE_FILE_NAME);</span>
|
|
<a id='x1-39411r202'></a><span class='ecrm-0500'>202</span>
|
|
<a id='x1-39413r203'></a><span class='ecrm-0500'>203</span><span class='ectt-0800'> pr_info(</span><span id='textcolor1147'><span class='ectt-0800'>"Device created on /dev/%s</span></span><span id='textcolor1148'><span class='ectt-0800'>\n</span></span><span id='textcolor1149'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>, DEVICE_FILE_NAME);</span>
|
|
<a id='x1-39415r204'></a><span class='ecrm-0500'>204</span>
|
|
<a id='x1-39417r205'></a><span class='ecrm-0500'>205</span><span class='ectt-0800'> </span><span id='textcolor1150'><span class='ectt-0800'>return</span></span><span class='ectt-0800'> 0;</span>
|
|
<a id='x1-39419r206'></a><span class='ecrm-0500'>206</span><span class='ectt-0800'>}</span>
|
|
<a id='x1-39421r207'></a><span class='ecrm-0500'>207</span>
|
|
<a id='x1-39423r208'></a><span class='ecrm-0500'>208</span><span id='textcolor1151'><span class='ectt-0800'>/* Cleanup - unregister the appropriate file from /proc */</span></span>
|
|
<a id='x1-39425r209'></a><span class='ecrm-0500'>209</span><span id='textcolor1152'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor1153'><span class='ectt-0800'>void</span></span><span class='ectt-0800'> __exit chardev2_exit(</span><span id='textcolor1154'><span class='ectt-0800'>void</span></span><span class='ectt-0800'>)</span>
|
|
<a id='x1-39427r210'></a><span class='ecrm-0500'>210</span><span class='ectt-0800'>{</span>
|
|
<a id='x1-39429r211'></a><span class='ecrm-0500'>211</span><span class='ectt-0800'> device_destroy(cls, MKDEV(MAJOR_NUM, 0));</span>
|
|
<a id='x1-39431r212'></a><span class='ecrm-0500'>212</span><span class='ectt-0800'> class_destroy(cls);</span>
|
|
<a id='x1-39433r213'></a><span class='ecrm-0500'>213</span>
|
|
<a id='x1-39435r214'></a><span class='ecrm-0500'>214</span><span class='ectt-0800'> </span><span id='textcolor1155'><span class='ectt-0800'>/* Unregister the device */</span></span>
|
|
<a id='x1-39437r215'></a><span class='ecrm-0500'>215</span><span class='ectt-0800'> unregister_chrdev(MAJOR_NUM, DEVICE_NAME);</span>
|
|
<a id='x1-39439r216'></a><span class='ecrm-0500'>216</span><span class='ectt-0800'>}</span>
|
|
<a id='x1-39441r217'></a><span class='ecrm-0500'>217</span>
|
|
<a id='x1-39443r218'></a><span class='ecrm-0500'>218</span><span class='ectt-0800'>module_init(chardev2_init);</span>
|
|
<a id='x1-39445r219'></a><span class='ecrm-0500'>219</span><span class='ectt-0800'>module_exit(chardev2_exit);</span>
|
|
<a id='x1-39447r220'></a><span class='ecrm-0500'>220</span>
|
|
<a id='x1-39449r221'></a><span class='ecrm-0500'>221</span><span class='ectt-0800'>MODULE_LICENSE(</span><span id='textcolor1156'><span class='ectt-0800'>"GPL"</span></span><span class='ectt-0800'>);</span></pre>
|
|
|
|
<!-- l. 1 --><p class='indent'>
|
|
</p>
|
|
<pre class='fancyvrb' id='fancyvrb50'><a id='x1-39451r1'></a><span class='ecrm-0500'>1</span><span id='textcolor1157'><span class='ectt-0800'>/*</span></span>
|
|
<a id='x1-39453r2'></a><span class='ecrm-0500'>2</span><span id='textcolor1158'><span class='ectt-0800'> * chardev.h - the header file with the ioctl definitions.</span></span>
|
|
<a id='x1-39455r3'></a><span class='ecrm-0500'>3</span><span id='textcolor1159'><span class='ectt-0800'> *</span></span>
|
|
<a id='x1-39457r4'></a><span class='ecrm-0500'>4</span><span id='textcolor1160'><span class='ectt-0800'> * The declarations here have to be in a header file, because they need</span></span>
|
|
<a id='x1-39459r5'></a><span class='ecrm-0500'>5</span><span id='textcolor1161'><span class='ectt-0800'> * to be known both to the kernel module (in chardev.c) and the process</span></span>
|
|
<a id='x1-39461r6'></a><span class='ecrm-0500'>6</span><span id='textcolor1162'><span class='ectt-0800'> * calling ioctl (ioctl.c).</span></span>
|
|
<a id='x1-39463r7'></a><span class='ecrm-0500'>7</span><span id='textcolor1163'><span class='ectt-0800'> */</span></span>
|
|
<a id='x1-39465r8'></a><span class='ecrm-0500'>8</span>
|
|
<a id='x1-39467r9'></a><span class='ecrm-0500'>9</span><span id='textcolor1164'><span class='ectt-0800'>#ifndef CHARDEV_H</span></span>
|
|
<a id='x1-39469r10'></a><span class='ecrm-0500'>10</span><span id='textcolor1165'><span class='ectt-0800'>#define CHARDEV_H</span></span>
|
|
<a id='x1-39471r11'></a><span class='ecrm-0500'>11</span>
|
|
<a id='x1-39473r12'></a><span class='ecrm-0500'>12</span><span id='textcolor1166'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor1167'><span class='ectt-0800'><linux/ioctl.h></span></span>
|
|
<a id='x1-39475r13'></a><span class='ecrm-0500'>13</span>
|
|
<a id='x1-39477r14'></a><span class='ecrm-0500'>14</span><span id='textcolor1168'><span class='ectt-0800'>/* The major device number. We can not rely on dynamic registration</span></span>
|
|
<a id='x1-39479r15'></a><span class='ecrm-0500'>15</span><span id='textcolor1169'><span class='ectt-0800'> * any more, because ioctls need to know it.</span></span>
|
|
<a id='x1-39481r16'></a><span class='ecrm-0500'>16</span><span id='textcolor1170'><span class='ectt-0800'> */</span></span>
|
|
<a id='x1-39483r17'></a><span class='ecrm-0500'>17</span><span id='textcolor1171'><span class='ectt-0800'>#define MAJOR_NUM 100</span></span>
|
|
<a id='x1-39485r18'></a><span class='ecrm-0500'>18</span>
|
|
<a id='x1-39487r19'></a><span class='ecrm-0500'>19</span><span id='textcolor1172'><span class='ectt-0800'>/* Set the message of the device driver */</span></span>
|
|
<a id='x1-39489r20'></a><span class='ecrm-0500'>20</span><span id='textcolor1173'><span class='ectt-0800'>#define IOCTL_SET_MSG _IOW(MAJOR_NUM, 0, char *)</span></span>
|
|
<a id='x1-39491r21'></a><span class='ecrm-0500'>21</span><span id='textcolor1174'><span class='ectt-0800'>/* _IOW means that we are creating an ioctl command number for passing</span></span>
|
|
<a id='x1-39493r22'></a><span class='ecrm-0500'>22</span><span id='textcolor1175'><span class='ectt-0800'> * information from a user process to the kernel module.</span></span>
|
|
<a id='x1-39495r23'></a><span class='ecrm-0500'>23</span><span id='textcolor1176'><span class='ectt-0800'> *</span></span>
|
|
<a id='x1-39497r24'></a><span class='ecrm-0500'>24</span><span id='textcolor1177'><span class='ectt-0800'> * The first arguments, MAJOR_NUM, is the major device number we are using.</span></span>
|
|
<a id='x1-39499r25'></a><span class='ecrm-0500'>25</span><span id='textcolor1178'><span class='ectt-0800'> *</span></span>
|
|
<a id='x1-39501r26'></a><span class='ecrm-0500'>26</span><span id='textcolor1179'><span class='ectt-0800'> * The second argument is the number of the command (there could be several</span></span>
|
|
<a id='x1-39503r27'></a><span class='ecrm-0500'>27</span><span id='textcolor1180'><span class='ectt-0800'> * with different meanings).</span></span>
|
|
<a id='x1-39505r28'></a><span class='ecrm-0500'>28</span><span id='textcolor1181'><span class='ectt-0800'> *</span></span>
|
|
<a id='x1-39507r29'></a><span class='ecrm-0500'>29</span><span id='textcolor1182'><span class='ectt-0800'> * The third argument is the type we want to get from the process to the</span></span>
|
|
<a id='x1-39509r30'></a><span class='ecrm-0500'>30</span><span id='textcolor1183'><span class='ectt-0800'> * kernel.</span></span>
|
|
<a id='x1-39511r31'></a><span class='ecrm-0500'>31</span><span id='textcolor1184'><span class='ectt-0800'> */</span></span>
|
|
<a id='x1-39513r32'></a><span class='ecrm-0500'>32</span>
|
|
<a id='x1-39515r33'></a><span class='ecrm-0500'>33</span><span id='textcolor1185'><span class='ectt-0800'>/* Get the message of the device driver */</span></span>
|
|
<a id='x1-39517r34'></a><span class='ecrm-0500'>34</span><span id='textcolor1186'><span class='ectt-0800'>#define IOCTL_GET_MSG _IOR(MAJOR_NUM, 1, char *)</span></span>
|
|
<a id='x1-39519r35'></a><span class='ecrm-0500'>35</span><span id='textcolor1187'><span class='ectt-0800'>/* This IOCTL is used for output, to get the message of the device driver.</span></span>
|
|
<a id='x1-39521r36'></a><span class='ecrm-0500'>36</span><span id='textcolor1188'><span class='ectt-0800'> * However, we still need the buffer to place the message in to be input,</span></span>
|
|
<a id='x1-39523r37'></a><span class='ecrm-0500'>37</span><span id='textcolor1189'><span class='ectt-0800'> * as it is allocated by the process.</span></span>
|
|
<a id='x1-39525r38'></a><span class='ecrm-0500'>38</span><span id='textcolor1190'><span class='ectt-0800'> */</span></span>
|
|
<a id='x1-39527r39'></a><span class='ecrm-0500'>39</span>
|
|
<a id='x1-39529r40'></a><span class='ecrm-0500'>40</span><span id='textcolor1191'><span class='ectt-0800'>/* Get the n</span><span class='tctt-0800'>'</span><span class='ectt-0800'>th byte of the message */</span></span>
|
|
<a id='x1-39531r41'></a><span class='ecrm-0500'>41</span><span id='textcolor1192'><span class='ectt-0800'>#define IOCTL_GET_NTH_BYTE _IOWR(MAJOR_NUM, 2, int)</span></span>
|
|
<a id='x1-39533r42'></a><span class='ecrm-0500'>42</span><span id='textcolor1193'><span class='ectt-0800'>/* The IOCTL is used for both input and output. It receives from the user</span></span>
|
|
<a id='x1-39535r43'></a><span class='ecrm-0500'>43</span><span id='textcolor1194'><span class='ectt-0800'> * a number, n, and returns message[n].</span></span>
|
|
<a id='x1-39537r44'></a><span class='ecrm-0500'>44</span><span id='textcolor1195'><span class='ectt-0800'> */</span></span>
|
|
<a id='x1-39539r45'></a><span class='ecrm-0500'>45</span>
|
|
<a id='x1-39541r46'></a><span class='ecrm-0500'>46</span><span id='textcolor1196'><span class='ectt-0800'>/* The name of the device file */</span></span>
|
|
<a id='x1-39543r47'></a><span class='ecrm-0500'>47</span><span id='textcolor1197'><span class='ectt-0800'>#define DEVICE_FILE_NAME "char_dev"</span></span>
|
|
<a id='x1-39545r48'></a><span class='ecrm-0500'>48</span>
|
|
<a id='x1-39547r49'></a><span class='ecrm-0500'>49</span><span id='textcolor1198'><span class='ectt-0800'>#endif</span></span></pre>
|
|
|
|
<!-- l. 1 --><p class='indent'>
|
|
</p>
|
|
<pre class='fancyvrb' id='fancyvrb51'><a id='x1-39549r1'></a><span class='ecrm-0500'>1</span><span id='textcolor1199'><span class='ectt-0800'>/*</span></span>
|
|
<a id='x1-39551r2'></a><span class='ecrm-0500'>2</span><span id='textcolor1200'><span class='ectt-0800'> * ioctl.c</span></span>
|
|
<a id='x1-39553r3'></a><span class='ecrm-0500'>3</span><span id='textcolor1201'><span class='ectt-0800'> */</span></span>
|
|
<a id='x1-39555r4'></a><span class='ecrm-0500'>4</span><span id='textcolor1202'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor1203'><span class='ectt-0800'><linux/cdev.h></span></span>
|
|
<a id='x1-39557r5'></a><span class='ecrm-0500'>5</span><span id='textcolor1204'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor1205'><span class='ectt-0800'><linux/fs.h></span></span>
|
|
<a id='x1-39559r6'></a><span class='ecrm-0500'>6</span><span id='textcolor1206'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor1207'><span class='ectt-0800'><linux/init.h></span></span>
|
|
<a id='x1-39561r7'></a><span class='ecrm-0500'>7</span><span id='textcolor1208'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor1209'><span class='ectt-0800'><linux/ioctl.h></span></span>
|
|
<a id='x1-39563r8'></a><span class='ecrm-0500'>8</span><span id='textcolor1210'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor1211'><span class='ectt-0800'><linux/module.h></span></span>
|
|
<a id='x1-39565r9'></a><span class='ecrm-0500'>9</span><span id='textcolor1212'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor1213'><span class='ectt-0800'><linux/slab.h></span></span>
|
|
<a id='x1-39567r10'></a><span class='ecrm-0500'>10</span><span id='textcolor1214'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor1215'><span class='ectt-0800'><linux/uaccess.h></span></span>
|
|
<a id='x1-39569r11'></a><span class='ecrm-0500'>11</span>
|
|
<a id='x1-39571r12'></a><span class='ecrm-0500'>12</span><span id='textcolor1216'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> ioctl_arg {</span>
|
|
<a id='x1-39573r13'></a><span class='ecrm-0500'>13</span><span class='ectt-0800'> </span><span id='textcolor1217'><span class='ectt-0800'>unsigned</span></span><span class='ectt-0800'> </span><span id='textcolor1218'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> reg;</span>
|
|
<a id='x1-39575r14'></a><span class='ecrm-0500'>14</span><span class='ectt-0800'> </span><span id='textcolor1219'><span class='ectt-0800'>unsigned</span></span><span class='ectt-0800'> </span><span id='textcolor1220'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> val;</span>
|
|
<a id='x1-39577r15'></a><span class='ecrm-0500'>15</span><span class='ectt-0800'>};</span>
|
|
<a id='x1-39579r16'></a><span class='ecrm-0500'>16</span>
|
|
<a id='x1-39581r17'></a><span class='ecrm-0500'>17</span><span id='textcolor1221'><span class='ectt-0800'>/* Documentation/ioctl/ioctl-number.txt */</span></span>
|
|
<a id='x1-39583r18'></a><span class='ecrm-0500'>18</span><span id='textcolor1222'><span class='ectt-0800'>#define IOC_MAGIC </span><span class='tctt-0800'>'</span><span class='ectt-0800'>\x66</span><span class='tctt-0800'>'</span></span>
|
|
<a id='x1-39585r19'></a><span class='ecrm-0500'>19</span>
|
|
<a id='x1-39587r20'></a><span class='ecrm-0500'>20</span><span id='textcolor1223'><span class='ectt-0800'>#define IOCTL_VALSET _IOW(IOC_MAGIC, 0, struct ioctl_arg)</span></span>
|
|
<a id='x1-39589r21'></a><span class='ecrm-0500'>21</span><span id='textcolor1224'><span class='ectt-0800'>#define IOCTL_VALGET _IOR(IOC_MAGIC, 1, struct ioctl_arg)</span></span>
|
|
<a id='x1-39591r22'></a><span class='ecrm-0500'>22</span><span id='textcolor1225'><span class='ectt-0800'>#define IOCTL_VALGET_NUM _IOR(IOC_MAGIC, 2, int)</span></span>
|
|
<a id='x1-39593r23'></a><span class='ecrm-0500'>23</span><span id='textcolor1226'><span class='ectt-0800'>#define IOCTL_VALSET_NUM _IOW(IOC_MAGIC, 3, int)</span></span>
|
|
<a id='x1-39595r24'></a><span class='ecrm-0500'>24</span>
|
|
<a id='x1-39597r25'></a><span class='ecrm-0500'>25</span><span id='textcolor1227'><span class='ectt-0800'>#define IOCTL_VAL_MAXNR 3</span></span>
|
|
<a id='x1-39599r26'></a><span class='ecrm-0500'>26</span><span id='textcolor1228'><span class='ectt-0800'>#define DRIVER_NAME "ioctltest"</span></span>
|
|
<a id='x1-39601r27'></a><span class='ecrm-0500'>27</span>
|
|
<a id='x1-39603r28'></a><span class='ecrm-0500'>28</span><span id='textcolor1229'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor1230'><span class='ectt-0800'>unsigned</span></span><span class='ectt-0800'> </span><span id='textcolor1231'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> test_ioctl_major = 0;</span>
|
|
<a id='x1-39605r29'></a><span class='ecrm-0500'>29</span><span id='textcolor1232'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor1233'><span class='ectt-0800'>unsigned</span></span><span class='ectt-0800'> </span><span id='textcolor1234'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> num_of_dev = 1;</span>
|
|
<a id='x1-39607r30'></a><span class='ecrm-0500'>30</span><span id='textcolor1235'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor1236'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> cdev test_ioctl_cdev;</span>
|
|
<a id='x1-39609r31'></a><span class='ecrm-0500'>31</span><span id='textcolor1237'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor1238'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> ioctl_num = 0;</span>
|
|
<a id='x1-39611r32'></a><span class='ecrm-0500'>32</span>
|
|
<a id='x1-39613r33'></a><span class='ecrm-0500'>33</span><span id='textcolor1239'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> test_ioctl_data {</span>
|
|
<a id='x1-39615r34'></a><span class='ecrm-0500'>34</span><span class='ectt-0800'> </span><span id='textcolor1240'><span class='ectt-0800'>unsigned</span></span><span class='ectt-0800'> </span><span id='textcolor1241'><span class='ectt-0800'>char</span></span><span class='ectt-0800'> val;</span>
|
|
<a id='x1-39617r35'></a><span class='ecrm-0500'>35</span><span class='ectt-0800'> rwlock_t lock;</span>
|
|
<a id='x1-39619r36'></a><span class='ecrm-0500'>36</span><span class='ectt-0800'>};</span>
|
|
<a id='x1-39621r37'></a><span class='ecrm-0500'>37</span>
|
|
<a id='x1-39623r38'></a><span class='ecrm-0500'>38</span><span id='textcolor1242'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor1243'><span class='ectt-0800'>long</span></span><span class='ectt-0800'> test_ioctl_ioctl(</span><span id='textcolor1244'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> file *filp, </span><span id='textcolor1245'><span class='ectt-0800'>unsigned</span></span><span class='ectt-0800'> </span><span id='textcolor1246'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> cmd,</span>
|
|
<a id='x1-39625r39'></a><span class='ecrm-0500'>39</span><span class='ectt-0800'> </span><span id='textcolor1247'><span class='ectt-0800'>unsigned</span></span><span class='ectt-0800'> </span><span id='textcolor1248'><span class='ectt-0800'>long</span></span><span class='ectt-0800'> arg)</span>
|
|
<a id='x1-39627r40'></a><span class='ecrm-0500'>40</span><span class='ectt-0800'>{</span>
|
|
<a id='x1-39629r41'></a><span class='ecrm-0500'>41</span><span class='ectt-0800'> </span><span id='textcolor1249'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> test_ioctl_data *ioctl_data = filp->private_data;</span>
|
|
<a id='x1-39631r42'></a><span class='ecrm-0500'>42</span><span class='ectt-0800'> </span><span id='textcolor1250'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> retval = 0;</span>
|
|
<a id='x1-39633r43'></a><span class='ecrm-0500'>43</span><span class='ectt-0800'> </span><span id='textcolor1251'><span class='ectt-0800'>unsigned</span></span><span class='ectt-0800'> </span><span id='textcolor1252'><span class='ectt-0800'>char</span></span><span class='ectt-0800'> val;</span>
|
|
<a id='x1-39635r44'></a><span class='ecrm-0500'>44</span><span class='ectt-0800'> </span><span id='textcolor1253'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> ioctl_arg data;</span>
|
|
<a id='x1-39637r45'></a><span class='ecrm-0500'>45</span><span class='ectt-0800'> memset(&data, 0, </span><span id='textcolor1254'><span class='ectt-0800'>sizeof</span></span><span class='ectt-0800'>(data));</span>
|
|
<a id='x1-39639r46'></a><span class='ecrm-0500'>46</span>
|
|
<a id='x1-39641r47'></a><span class='ecrm-0500'>47</span><span class='ectt-0800'> </span><span id='textcolor1255'><span class='ectt-0800'>switch</span></span><span class='ectt-0800'> (cmd) {</span>
|
|
<a id='x1-39643r48'></a><span class='ecrm-0500'>48</span><span class='ectt-0800'> </span><span id='textcolor1256'><span class='ectt-0800'>case</span></span><span class='ectt-0800'> IOCTL_VALSET:</span>
|
|
<a id='x1-39645r49'></a><span class='ecrm-0500'>49</span><span class='ectt-0800'> </span><span id='textcolor1257'><span class='ectt-0800'>if</span></span><span class='ectt-0800'> (copy_from_user(&data, (</span><span id='textcolor1258'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> __user *)arg, </span><span id='textcolor1259'><span class='ectt-0800'>sizeof</span></span><span class='ectt-0800'>(data))) {</span>
|
|
<a id='x1-39647r50'></a><span class='ecrm-0500'>50</span><span class='ectt-0800'> retval = -EFAULT;</span>
|
|
<a id='x1-39649r51'></a><span class='ecrm-0500'>51</span><span class='ectt-0800'> </span><span id='textcolor1260'><span class='ectt-0800'>goto</span></span><span class='ectt-0800'> done;</span>
|
|
<a id='x1-39651r52'></a><span class='ecrm-0500'>52</span><span class='ectt-0800'> }</span>
|
|
<a id='x1-39653r53'></a><span class='ecrm-0500'>53</span>
|
|
<a id='x1-39655r54'></a><span class='ecrm-0500'>54</span><span class='ectt-0800'> pr_alert(</span><span id='textcolor1261'><span class='ectt-0800'>"IOCTL set val:%x .</span></span><span id='textcolor1262'><span class='ectt-0800'>\n</span></span><span id='textcolor1263'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>, data.val);</span>
|
|
<a id='x1-39657r55'></a><span class='ecrm-0500'>55</span><span class='ectt-0800'> write_lock(&ioctl_data->lock);</span>
|
|
<a id='x1-39659r56'></a><span class='ecrm-0500'>56</span><span class='ectt-0800'> ioctl_data->val = data.val;</span>
|
|
<a id='x1-39661r57'></a><span class='ecrm-0500'>57</span><span class='ectt-0800'> write_unlock(&ioctl_data->lock);</span>
|
|
<a id='x1-39663r58'></a><span class='ecrm-0500'>58</span><span class='ectt-0800'> </span><span id='textcolor1264'><span class='ectt-0800'>break</span></span><span class='ectt-0800'>;</span>
|
|
<a id='x1-39665r59'></a><span class='ecrm-0500'>59</span>
|
|
<a id='x1-39667r60'></a><span class='ecrm-0500'>60</span><span class='ectt-0800'> </span><span id='textcolor1265'><span class='ectt-0800'>case</span></span><span class='ectt-0800'> IOCTL_VALGET:</span>
|
|
<a id='x1-39669r61'></a><span class='ecrm-0500'>61</span><span class='ectt-0800'> read_lock(&ioctl_data->lock);</span>
|
|
<a id='x1-39671r62'></a><span class='ecrm-0500'>62</span><span class='ectt-0800'> val = ioctl_data->val;</span>
|
|
<a id='x1-39673r63'></a><span class='ecrm-0500'>63</span><span class='ectt-0800'> read_unlock(&ioctl_data->lock);</span>
|
|
<a id='x1-39675r64'></a><span class='ecrm-0500'>64</span><span class='ectt-0800'> data.val = val;</span>
|
|
<a id='x1-39677r65'></a><span class='ecrm-0500'>65</span>
|
|
<a id='x1-39679r66'></a><span class='ecrm-0500'>66</span><span class='ectt-0800'> </span><span id='textcolor1266'><span class='ectt-0800'>if</span></span><span class='ectt-0800'> (copy_to_user((</span><span id='textcolor1267'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> __user *)arg, &data, </span><span id='textcolor1268'><span class='ectt-0800'>sizeof</span></span><span class='ectt-0800'>(data))) {</span>
|
|
<a id='x1-39681r67'></a><span class='ecrm-0500'>67</span><span class='ectt-0800'> retval = -EFAULT;</span>
|
|
<a id='x1-39683r68'></a><span class='ecrm-0500'>68</span><span class='ectt-0800'> </span><span id='textcolor1269'><span class='ectt-0800'>goto</span></span><span class='ectt-0800'> done;</span>
|
|
<a id='x1-39685r69'></a><span class='ecrm-0500'>69</span><span class='ectt-0800'> }</span>
|
|
<a id='x1-39687r70'></a><span class='ecrm-0500'>70</span>
|
|
<a id='x1-39689r71'></a><span class='ecrm-0500'>71</span><span class='ectt-0800'> </span><span id='textcolor1270'><span class='ectt-0800'>break</span></span><span class='ectt-0800'>;</span>
|
|
<a id='x1-39691r72'></a><span class='ecrm-0500'>72</span>
|
|
<a id='x1-39693r73'></a><span class='ecrm-0500'>73</span><span class='ectt-0800'> </span><span id='textcolor1271'><span class='ectt-0800'>case</span></span><span class='ectt-0800'> IOCTL_VALGET_NUM:</span>
|
|
<a id='x1-39695r74'></a><span class='ecrm-0500'>74</span><span class='ectt-0800'> retval = __put_user(ioctl_num, (</span><span id='textcolor1272'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> __user *)arg);</span>
|
|
<a id='x1-39697r75'></a><span class='ecrm-0500'>75</span><span class='ectt-0800'> </span><span id='textcolor1273'><span class='ectt-0800'>break</span></span><span class='ectt-0800'>;</span>
|
|
<a id='x1-39699r76'></a><span class='ecrm-0500'>76</span>
|
|
<a id='x1-39701r77'></a><span class='ecrm-0500'>77</span><span class='ectt-0800'> </span><span id='textcolor1274'><span class='ectt-0800'>case</span></span><span class='ectt-0800'> IOCTL_VALSET_NUM:</span>
|
|
<a id='x1-39703r78'></a><span class='ecrm-0500'>78</span><span class='ectt-0800'> ioctl_num = arg;</span>
|
|
<a id='x1-39705r79'></a><span class='ecrm-0500'>79</span><span class='ectt-0800'> </span><span id='textcolor1275'><span class='ectt-0800'>break</span></span><span class='ectt-0800'>;</span>
|
|
<a id='x1-39707r80'></a><span class='ecrm-0500'>80</span>
|
|
<a id='x1-39709r81'></a><span class='ecrm-0500'>81</span><span class='ectt-0800'> </span><span id='textcolor1276'><span class='ectt-0800'>default</span></span><span class='ectt-0800'>:</span>
|
|
<a id='x1-39711r82'></a><span class='ecrm-0500'>82</span><span class='ectt-0800'> retval = -ENOTTY;</span>
|
|
<a id='x1-39713r83'></a><span class='ecrm-0500'>83</span><span class='ectt-0800'> }</span>
|
|
<a id='x1-39715r84'></a><span class='ecrm-0500'>84</span>
|
|
<a id='x1-39717r85'></a><span class='ecrm-0500'>85</span><span class='ectt-0800'>done:</span>
|
|
<a id='x1-39719r86'></a><span class='ecrm-0500'>86</span><span class='ectt-0800'> </span><span id='textcolor1277'><span class='ectt-0800'>return</span></span><span class='ectt-0800'> retval;</span>
|
|
<a id='x1-39721r87'></a><span class='ecrm-0500'>87</span><span class='ectt-0800'>}</span>
|
|
<a id='x1-39723r88'></a><span class='ecrm-0500'>88</span>
|
|
<a id='x1-39725r89'></a><span class='ecrm-0500'>89</span><span id='textcolor1278'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor1279'><span class='ectt-0800'>ssize_t</span></span><span class='ectt-0800'> test_ioctl_read(</span><span id='textcolor1280'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> file *filp, </span><span id='textcolor1281'><span class='ectt-0800'>char</span></span><span class='ectt-0800'> __user *buf,</span>
|
|
<a id='x1-39727r90'></a><span class='ecrm-0500'>90</span><span class='ectt-0800'> </span><span id='textcolor1282'><span class='ectt-0800'>size_t</span></span><span class='ectt-0800'> count, loff_t *f_pos)</span>
|
|
<a id='x1-39729r91'></a><span class='ecrm-0500'>91</span><span class='ectt-0800'>{</span>
|
|
<a id='x1-39731r92'></a><span class='ecrm-0500'>92</span><span class='ectt-0800'> </span><span id='textcolor1283'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> test_ioctl_data *ioctl_data = filp->private_data;</span>
|
|
<a id='x1-39733r93'></a><span class='ecrm-0500'>93</span><span class='ectt-0800'> </span><span id='textcolor1284'><span class='ectt-0800'>unsigned</span></span><span class='ectt-0800'> </span><span id='textcolor1285'><span class='ectt-0800'>char</span></span><span class='ectt-0800'> val;</span>
|
|
<a id='x1-39735r94'></a><span class='ecrm-0500'>94</span><span class='ectt-0800'> </span><span id='textcolor1286'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> retval;</span>
|
|
<a id='x1-39737r95'></a><span class='ecrm-0500'>95</span><span class='ectt-0800'> </span><span id='textcolor1287'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> i = 0;</span>
|
|
<a id='x1-39739r96'></a><span class='ecrm-0500'>96</span>
|
|
<a id='x1-39741r97'></a><span class='ecrm-0500'>97</span><span class='ectt-0800'> read_lock(&ioctl_data->lock);</span>
|
|
<a id='x1-39743r98'></a><span class='ecrm-0500'>98</span><span class='ectt-0800'> val = ioctl_data->val;</span>
|
|
<a id='x1-39745r99'></a><span class='ecrm-0500'>99</span><span class='ectt-0800'> read_unlock(&ioctl_data->lock);</span>
|
|
<a id='x1-39747r100'></a><span class='ecrm-0500'>100</span>
|
|
<a id='x1-39749r101'></a><span class='ecrm-0500'>101</span><span class='ectt-0800'> </span><span id='textcolor1288'><span class='ectt-0800'>for</span></span><span class='ectt-0800'> (; i < count; i++) {</span>
|
|
<a id='x1-39751r102'></a><span class='ecrm-0500'>102</span><span class='ectt-0800'> </span><span id='textcolor1289'><span class='ectt-0800'>if</span></span><span class='ectt-0800'> (copy_to_user(&buf[i], &val, 1)) {</span>
|
|
<a id='x1-39753r103'></a><span class='ecrm-0500'>103</span><span class='ectt-0800'> retval = -EFAULT;</span>
|
|
<a id='x1-39755r104'></a><span class='ecrm-0500'>104</span><span class='ectt-0800'> </span><span id='textcolor1290'><span class='ectt-0800'>goto</span></span><span class='ectt-0800'> out;</span>
|
|
<a id='x1-39757r105'></a><span class='ecrm-0500'>105</span><span class='ectt-0800'> }</span>
|
|
<a id='x1-39759r106'></a><span class='ecrm-0500'>106</span><span class='ectt-0800'> }</span>
|
|
<a id='x1-39761r107'></a><span class='ecrm-0500'>107</span>
|
|
<a id='x1-39763r108'></a><span class='ecrm-0500'>108</span><span class='ectt-0800'> retval = count;</span>
|
|
<a id='x1-39765r109'></a><span class='ecrm-0500'>109</span><span class='ectt-0800'>out:</span>
|
|
<a id='x1-39767r110'></a><span class='ecrm-0500'>110</span><span class='ectt-0800'> </span><span id='textcolor1291'><span class='ectt-0800'>return</span></span><span class='ectt-0800'> retval;</span>
|
|
<a id='x1-39769r111'></a><span class='ecrm-0500'>111</span><span class='ectt-0800'>}</span>
|
|
<a id='x1-39771r112'></a><span class='ecrm-0500'>112</span>
|
|
<a id='x1-39773r113'></a><span class='ecrm-0500'>113</span><span id='textcolor1292'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor1293'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> test_ioctl_close(</span><span id='textcolor1294'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> inode *inode, </span><span id='textcolor1295'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> file *filp)</span>
|
|
<a id='x1-39775r114'></a><span class='ecrm-0500'>114</span><span class='ectt-0800'>{</span>
|
|
<a id='x1-39777r115'></a><span class='ecrm-0500'>115</span><span class='ectt-0800'> pr_alert(</span><span id='textcolor1296'><span class='ectt-0800'>"%s call.</span></span><span id='textcolor1297'><span class='ectt-0800'>\n</span></span><span id='textcolor1298'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>, __func__);</span>
|
|
<a id='x1-39779r116'></a><span class='ecrm-0500'>116</span>
|
|
<a id='x1-39781r117'></a><span class='ecrm-0500'>117</span><span class='ectt-0800'> </span><span id='textcolor1299'><span class='ectt-0800'>if</span></span><span class='ectt-0800'> (filp->private_data) {</span>
|
|
<a id='x1-39783r118'></a><span class='ecrm-0500'>118</span><span class='ectt-0800'> kfree(filp->private_data);</span>
|
|
<a id='x1-39785r119'></a><span class='ecrm-0500'>119</span><span class='ectt-0800'> filp->private_data = NULL;</span>
|
|
<a id='x1-39787r120'></a><span class='ecrm-0500'>120</span><span class='ectt-0800'> }</span>
|
|
<a id='x1-39789r121'></a><span class='ecrm-0500'>121</span>
|
|
<a id='x1-39791r122'></a><span class='ecrm-0500'>122</span><span class='ectt-0800'> </span><span id='textcolor1300'><span class='ectt-0800'>return</span></span><span class='ectt-0800'> 0;</span>
|
|
<a id='x1-39793r123'></a><span class='ecrm-0500'>123</span><span class='ectt-0800'>}</span>
|
|
<a id='x1-39795r124'></a><span class='ecrm-0500'>124</span>
|
|
<a id='x1-39797r125'></a><span class='ecrm-0500'>125</span><span id='textcolor1301'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor1302'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> test_ioctl_open(</span><span id='textcolor1303'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> inode *inode, </span><span id='textcolor1304'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> file *filp)</span>
|
|
<a id='x1-39799r126'></a><span class='ecrm-0500'>126</span><span class='ectt-0800'>{</span>
|
|
<a id='x1-39801r127'></a><span class='ecrm-0500'>127</span><span class='ectt-0800'> </span><span id='textcolor1305'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> test_ioctl_data *ioctl_data;</span>
|
|
<a id='x1-39803r128'></a><span class='ecrm-0500'>128</span>
|
|
<a id='x1-39805r129'></a><span class='ecrm-0500'>129</span><span class='ectt-0800'> pr_alert(</span><span id='textcolor1306'><span class='ectt-0800'>"%s call.</span></span><span id='textcolor1307'><span class='ectt-0800'>\n</span></span><span id='textcolor1308'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>, __func__);</span>
|
|
<a id='x1-39807r130'></a><span class='ecrm-0500'>130</span><span class='ectt-0800'> ioctl_data = kmalloc(</span><span id='textcolor1309'><span class='ectt-0800'>sizeof</span></span><span class='ectt-0800'>(</span><span id='textcolor1310'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> test_ioctl_data), GFP_KERNEL);</span>
|
|
<a id='x1-39809r131'></a><span class='ecrm-0500'>131</span>
|
|
<a id='x1-39811r132'></a><span class='ecrm-0500'>132</span><span class='ectt-0800'> </span><span id='textcolor1311'><span class='ectt-0800'>if</span></span><span class='ectt-0800'> (ioctl_data == NULL)</span>
|
|
<a id='x1-39813r133'></a><span class='ecrm-0500'>133</span><span class='ectt-0800'> </span><span id='textcolor1312'><span class='ectt-0800'>return</span></span><span class='ectt-0800'> -ENOMEM;</span>
|
|
<a id='x1-39815r134'></a><span class='ecrm-0500'>134</span>
|
|
<a id='x1-39817r135'></a><span class='ecrm-0500'>135</span><span class='ectt-0800'> rwlock_init(&ioctl_data->lock);</span>
|
|
<a id='x1-39819r136'></a><span class='ecrm-0500'>136</span><span class='ectt-0800'> ioctl_data->val = 0xFF;</span>
|
|
<a id='x1-39821r137'></a><span class='ecrm-0500'>137</span><span class='ectt-0800'> filp->private_data = ioctl_data;</span>
|
|
<a id='x1-39823r138'></a><span class='ecrm-0500'>138</span>
|
|
<a id='x1-39825r139'></a><span class='ecrm-0500'>139</span><span class='ectt-0800'> </span><span id='textcolor1313'><span class='ectt-0800'>return</span></span><span class='ectt-0800'> 0;</span>
|
|
<a id='x1-39827r140'></a><span class='ecrm-0500'>140</span><span class='ectt-0800'>}</span>
|
|
<a id='x1-39829r141'></a><span class='ecrm-0500'>141</span>
|
|
<a id='x1-39831r142'></a><span class='ecrm-0500'>142</span><span id='textcolor1314'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor1315'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> file_operations fops = {</span>
|
|
<a id='x1-39833r143'></a><span class='ecrm-0500'>143</span><span class='ectt-0800'> .owner = THIS_MODULE,</span>
|
|
<a id='x1-39835r144'></a><span class='ecrm-0500'>144</span><span class='ectt-0800'> .open = test_ioctl_open,</span>
|
|
<a id='x1-39837r145'></a><span class='ecrm-0500'>145</span><span class='ectt-0800'> .release = test_ioctl_close,</span>
|
|
<a id='x1-39839r146'></a><span class='ecrm-0500'>146</span><span class='ectt-0800'> .read = test_ioctl_read,</span>
|
|
<a id='x1-39841r147'></a><span class='ecrm-0500'>147</span><span class='ectt-0800'> .unlocked_ioctl = test_ioctl_ioctl,</span>
|
|
<a id='x1-39843r148'></a><span class='ecrm-0500'>148</span><span class='ectt-0800'>};</span>
|
|
<a id='x1-39845r149'></a><span class='ecrm-0500'>149</span>
|
|
<a id='x1-39847r150'></a><span class='ecrm-0500'>150</span><span id='textcolor1316'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor1317'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> ioctl_init(</span><span id='textcolor1318'><span class='ectt-0800'>void</span></span><span class='ectt-0800'>)</span>
|
|
<a id='x1-39849r151'></a><span class='ecrm-0500'>151</span><span class='ectt-0800'>{</span>
|
|
<a id='x1-39851r152'></a><span class='ecrm-0500'>152</span><span class='ectt-0800'> </span><span id='textcolor1319'><span class='ectt-0800'>dev_t</span></span><span class='ectt-0800'> dev = MKDEV(test_ioctl_major, 0);</span>
|
|
<a id='x1-39853r153'></a><span class='ecrm-0500'>153</span><span class='ectt-0800'> </span><span id='textcolor1320'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> alloc_ret = 0;</span>
|
|
<a id='x1-39855r154'></a><span class='ecrm-0500'>154</span><span class='ectt-0800'> </span><span id='textcolor1321'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> cdev_ret = 0;</span>
|
|
<a id='x1-39857r155'></a><span class='ecrm-0500'>155</span><span class='ectt-0800'> alloc_ret = alloc_chrdev_region(&dev, 0, num_of_dev, DRIVER_NAME);</span>
|
|
<a id='x1-39859r156'></a><span class='ecrm-0500'>156</span>
|
|
<a id='x1-39861r157'></a><span class='ecrm-0500'>157</span><span class='ectt-0800'> </span><span id='textcolor1322'><span class='ectt-0800'>if</span></span><span class='ectt-0800'> (alloc_ret)</span>
|
|
<a id='x1-39863r158'></a><span class='ecrm-0500'>158</span><span class='ectt-0800'> </span><span id='textcolor1323'><span class='ectt-0800'>goto</span></span><span class='ectt-0800'> error;</span>
|
|
<a id='x1-39865r159'></a><span class='ecrm-0500'>159</span>
|
|
<a id='x1-39867r160'></a><span class='ecrm-0500'>160</span><span class='ectt-0800'> test_ioctl_major = MAJOR(dev);</span>
|
|
<a id='x1-39869r161'></a><span class='ecrm-0500'>161</span><span class='ectt-0800'> cdev_init(&test_ioctl_cdev, &fops);</span>
|
|
<a id='x1-39871r162'></a><span class='ecrm-0500'>162</span><span class='ectt-0800'> cdev_ret = cdev_add(&test_ioctl_cdev, dev, num_of_dev);</span>
|
|
<a id='x1-39873r163'></a><span class='ecrm-0500'>163</span>
|
|
<a id='x1-39875r164'></a><span class='ecrm-0500'>164</span><span class='ectt-0800'> </span><span id='textcolor1324'><span class='ectt-0800'>if</span></span><span class='ectt-0800'> (cdev_ret)</span>
|
|
<a id='x1-39877r165'></a><span class='ecrm-0500'>165</span><span class='ectt-0800'> </span><span id='textcolor1325'><span class='ectt-0800'>goto</span></span><span class='ectt-0800'> error;</span>
|
|
<a id='x1-39879r166'></a><span class='ecrm-0500'>166</span>
|
|
<a id='x1-39881r167'></a><span class='ecrm-0500'>167</span><span class='ectt-0800'> pr_alert(</span><span id='textcolor1326'><span class='ectt-0800'>"%s driver(major: %d) installed.</span></span><span id='textcolor1327'><span class='ectt-0800'>\n</span></span><span id='textcolor1328'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>, DRIVER_NAME,</span>
|
|
<a id='x1-39883r168'></a><span class='ecrm-0500'>168</span><span class='ectt-0800'> test_ioctl_major);</span>
|
|
<a id='x1-39885r169'></a><span class='ecrm-0500'>169</span><span class='ectt-0800'> </span><span id='textcolor1329'><span class='ectt-0800'>return</span></span><span class='ectt-0800'> 0;</span>
|
|
<a id='x1-39887r170'></a><span class='ecrm-0500'>170</span><span class='ectt-0800'>error:</span>
|
|
<a id='x1-39889r171'></a><span class='ecrm-0500'>171</span><span class='ectt-0800'> </span><span id='textcolor1330'><span class='ectt-0800'>if</span></span><span class='ectt-0800'> (cdev_ret == 0)</span>
|
|
<a id='x1-39891r172'></a><span class='ecrm-0500'>172</span><span class='ectt-0800'> cdev_del(&test_ioctl_cdev);</span>
|
|
<a id='x1-39893r173'></a><span class='ecrm-0500'>173</span><span class='ectt-0800'> </span><span id='textcolor1331'><span class='ectt-0800'>if</span></span><span class='ectt-0800'> (alloc_ret == 0)</span>
|
|
<a id='x1-39895r174'></a><span class='ecrm-0500'>174</span><span class='ectt-0800'> unregister_chrdev_region(dev, num_of_dev);</span>
|
|
<a id='x1-39897r175'></a><span class='ecrm-0500'>175</span><span class='ectt-0800'> </span><span id='textcolor1332'><span class='ectt-0800'>return</span></span><span class='ectt-0800'> -1;</span>
|
|
<a id='x1-39899r176'></a><span class='ecrm-0500'>176</span><span class='ectt-0800'>}</span>
|
|
<a id='x1-39901r177'></a><span class='ecrm-0500'>177</span>
|
|
<a id='x1-39903r178'></a><span class='ecrm-0500'>178</span><span id='textcolor1333'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor1334'><span class='ectt-0800'>void</span></span><span class='ectt-0800'> ioctl_exit(</span><span id='textcolor1335'><span class='ectt-0800'>void</span></span><span class='ectt-0800'>)</span>
|
|
<a id='x1-39905r179'></a><span class='ecrm-0500'>179</span><span class='ectt-0800'>{</span>
|
|
<a id='x1-39907r180'></a><span class='ecrm-0500'>180</span><span class='ectt-0800'> </span><span id='textcolor1336'><span class='ectt-0800'>dev_t</span></span><span class='ectt-0800'> dev = MKDEV(test_ioctl_major, 0);</span>
|
|
<a id='x1-39909r181'></a><span class='ecrm-0500'>181</span>
|
|
<a id='x1-39911r182'></a><span class='ecrm-0500'>182</span><span class='ectt-0800'> cdev_del(&test_ioctl_cdev);</span>
|
|
<a id='x1-39913r183'></a><span class='ecrm-0500'>183</span><span class='ectt-0800'> unregister_chrdev_region(dev, num_of_dev);</span>
|
|
<a id='x1-39915r184'></a><span class='ecrm-0500'>184</span><span class='ectt-0800'> pr_alert(</span><span id='textcolor1337'><span class='ectt-0800'>"%s driver removed.</span></span><span id='textcolor1338'><span class='ectt-0800'>\n</span></span><span id='textcolor1339'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>, DRIVER_NAME);</span>
|
|
<a id='x1-39917r185'></a><span class='ecrm-0500'>185</span><span class='ectt-0800'>}</span>
|
|
<a id='x1-39919r186'></a><span class='ecrm-0500'>186</span>
|
|
<a id='x1-39921r187'></a><span class='ecrm-0500'>187</span><span class='ectt-0800'>module_init(ioctl_init);</span>
|
|
<a id='x1-39923r188'></a><span class='ecrm-0500'>188</span><span class='ectt-0800'>module_exit(ioctl_exit);</span>
|
|
<a id='x1-39925r189'></a><span class='ecrm-0500'>189</span>
|
|
<a id='x1-39927r190'></a><span class='ecrm-0500'>190</span><span class='ectt-0800'>MODULE_LICENSE(</span><span id='textcolor1340'><span class='ectt-0800'>"GPL"</span></span><span class='ectt-0800'>);</span>
|
|
<a id='x1-39929r191'></a><span class='ecrm-0500'>191</span><span class='ectt-0800'>MODULE_DESCRIPTION(</span><span id='textcolor1341'><span class='ectt-0800'>"This is test_ioctl module"</span></span><span class='ectt-0800'>);</span></pre>
|
|
|
|
|
|
|
|
<!-- l. 1176 --><p class='noindent'>
|
|
</p>
|
|
<h3 class='sectionHead' id='system-calls'><span class='titlemark'>10 </span> <a id='x1-4000010'></a>System Calls</h3>
|
|
<!-- l. 1178 --><p class='noindent'>So far, the only thing we’ve done was to use well defined kernel mechanisms to
|
|
register <span class='obeylines-h'><span class='verb'><span class='ectt-1000'>/proc</span></span></span> files and device handlers. This is fine if you want to do something the
|
|
kernel programmers thought you’d want, such as write a device driver. But what if
|
|
you want to do something unusual, to change the behavior of the system in some
|
|
way? Then, you are mostly on your own.
|
|
</p><!-- l. 1183 --><p class='indent'> If you are not being sensible and using a virtual machine then this is where kernel
|
|
programming can become hazardous. While writing the example below, I killed the
|
|
<code> <span class='ectt-1000'>open()</span>
|
|
</code> system call. This meant I could not open any files, I could not run any
|
|
programs, and I could not shutdown the system. I had to restart the virtual
|
|
machine. No important files got annihilated, but if I was doing this on some live
|
|
mission critical system then that could have been a possible outcome. To
|
|
ensure you do not lose any files, even within a test environment, please run
|
|
<code> <span class='ectt-1000'>sync</span>
|
|
</code> right before you do the <code> <span class='ectt-1000'>insmod</span>
|
|
</code> and the <code> <span class='ectt-1000'>rmmod</span>
|
|
</code>.
|
|
</p><!-- l. 1190 --><p class='indent'> Forget about <span class='obeylines-h'><span class='verb'><span class='ectt-1000'>/proc</span></span></span> files, forget about device files. They are just minor details.
|
|
Minutiae in the vast expanse of the universe. The real process to kernel
|
|
communication mechanism, the one used by all processes, is <span class='ecti-1000'>system calls</span>. When a
|
|
process requests a service from the kernel (such as opening a file, forking to a new
|
|
process, or requesting more memory), this is the mechanism used. If you want to
|
|
change the behaviour of the kernel in interesting ways, this is the place to do
|
|
it. By the way, if you want to see which system calls a program uses, run
|
|
<code> <span class='ectt-1000'>strace <arguments></span>
|
|
</code>.
|
|
</p><!-- l. 1198 --><p class='indent'> In general, a process is not supposed to be able to access the kernel. It can not
|
|
access kernel memory and it can’t call kernel functions. The hardware of the CPU
|
|
enforces this (that is the reason why it is called “protected mode” or “page
|
|
protection”).
|
|
</p><!-- l. 1202 --><p class='indent'> System calls are an exception to this general rule. What happens is that the
|
|
process fills the registers with the appropriate values and then calls a special
|
|
instruction which jumps to a previously defined location in the kernel (of course, that
|
|
location is readable by user processes, it is not writable by them). Under Intel CPUs,
|
|
this is done by means of interrupt 0x80. The hardware knows that once you jump to
|
|
this location, you are no longer running in restricted user mode, but as the
|
|
operating system kernel — and therefore you’re allowed to do whatever you
|
|
want.
|
|
</p><!-- l. 1207 --><p class='indent'> The location in the kernel a process can jump to is called <span class='obeylines-h'><span class='verb'><span class='ectt-1000'>system_call</span></span></span>. The
|
|
procedure at that location checks the system call number, which tells the kernel what
|
|
service the process requested. Then, it looks at the table of system calls
|
|
(<code> <span class='ectt-1000'>sys_call_table</span>
|
|
</code>) to see the address of the kernel function to call. Then it calls the function, and after
|
|
|
|
|
|
|
|
it returns, does a few system checks and then return back to the process (or to a
|
|
different process, if the process time ran out). If you want to read this code, it is
|
|
at the source file <span class='obeylines-h'><span class='verb'><span class='ectt-1000'>arch/$(architecture)/kernel/entry.S</span></span></span>, after the line
|
|
<code> <span class='ectt-1000'>ENTRY(system_call)</span>
|
|
</code>.
|
|
</p><!-- l. 1213 --><p class='indent'> So, if we want to change the way a certain system call works, what we need to do
|
|
is to write our own function to implement it (usually by adding a bit of our own
|
|
code, and then calling the original function) and then change the pointer at
|
|
<code> <span class='ectt-1000'>sys_call_table</span>
|
|
</code> to point to our function. Because we might be removed later and we
|
|
don’t want to leave the system in an unstable state, it’s important for
|
|
<code> <span class='ectt-1000'>cleanup_module</span>
|
|
</code> to restore the table to its original state.
|
|
</p><!-- l. 1216 --><p class='indent'> To modify the content of <code> <span class='ectt-1000'>sys_call_table</span>
|
|
</code>, we need to consider the control register. A control register is a processor
|
|
register that changes or controls the general behavior of the CPU. For x86
|
|
architecture, the <span class='obeylines-h'><span class='verb'><span class='ectt-1000'>cr0</span></span></span> register has various control flags that modify the basic
|
|
operation of the processor. The <span class='obeylines-h'><span class='verb'><span class='ectt-1000'>WP</span></span></span> flag in <span class='obeylines-h'><span class='verb'><span class='ectt-1000'>cr0</span></span></span> stands for write protection.
|
|
Once the <span class='obeylines-h'><span class='verb'><span class='ectt-1000'>WP</span></span></span> flag is set, the processor disallows further write attempts to the
|
|
read-only sections Therefore, we must disable the <span class='obeylines-h'><span class='verb'><span class='ectt-1000'>WP</span></span></span> flag before modifying
|
|
<code> <span class='ectt-1000'>sys_call_table</span>
|
|
</code>. Since Linux v5.3, the <code> <span class='ectt-1000'>write_cr0</span>
|
|
</code> function cannot be used because of the sensitive <span class='obeylines-h'><span class='verb'><span class='ectt-1000'>cr0</span></span></span> bits pinned by the security
|
|
issue, the attacker may write into CPU control registers to disable CPU protections
|
|
like write protection. As a result, we have to provide the custom assembly routine to
|
|
bypass it.
|
|
</p><!-- l. 1225 --><p class='indent'> However, <code> <span class='ectt-1000'>sys_call_table</span>
|
|
</code> symbol is unexported to prevent misuse. But there have few ways to get the symbol, manual
|
|
symbol lookup and <code> <span class='ectt-1000'>kallsyms_lookup_name</span>
|
|
</code>. Here we use both depend on the kernel version.
|
|
</p><!-- l. 1229 --><p class='indent'> Because of the <span class='ecti-1000'>control-flow integrity</span>, which is a technique to prevent the redirect
|
|
execution code from the attacker, for making sure that the indirect calls go to the
|
|
expected addresses and the return addresses are not changed. Since Linux v5.7, the
|
|
kernel patched the series of <span class='ecti-1000'>control-flow enforcement </span>(CET) for x86, and some
|
|
configurations of GCC, like GCC versions 9 and 10 in Ubuntu, will add with CET
|
|
(the <span class='obeylines-h'><span class='verb'><span class='ectt-1000'>-fcf-protection</span></span></span> option) in the kernel by default. Using that GCC to compile
|
|
the kernel with retpoline off may result in CET being enabled in the kernel. You can
|
|
use the following command to check out the <span class='obeylines-h'><span class='verb'><span class='ectt-1000'>-fcf-protection</span></span></span> option is enabled or
|
|
not:
|
|
|
|
|
|
|
|
</p>
|
|
<pre class='verbatim' id='verbatim-11'>
|
|
$ gcc -v -Q -O2 --help=target | grep protection
|
|
Using built-in specs.
|
|
COLLECT_GCC=gcc
|
|
COLLECT_LTO_WRAPPER=/usr/lib/gcc/x86_64-linux-gnu/9/lto-wrapper
|
|
...
|
|
gcc version 9.3.0 (Ubuntu 9.3.0-17ubuntu1~20.04)
|
|
COLLECT_GCC_OPTIONS='-v' '-Q' '-O2' '--help=target' '-mtune=generic' '-march=x86-64'
|
|
/usr/lib/gcc/x86_64-linux-gnu/9/cc1 -v ... -fcf-protection ...
|
|
GNU C17 (Ubuntu 9.3.0-17ubuntu1~20.04) version 9.3.0 (x86_64-linux-gnu)
|
|
...
|
|
</pre>
|
|
<!-- l. 1244 --><p class='nopar'>But CET should not be enabled in the kernel, it may break the Kprobes and bpf.
|
|
Consequently, CET is disabled since v5.11. To guarantee the manual symbol lookup
|
|
worked, we only use up to v5.4.
|
|
</p><!-- l. 1249 --><p class='indent'> Unfortunately, since Linux v5.7 <code> <span class='ectt-1000'>kallsyms_lookup_name</span>
|
|
</code> is also unexported, it needs certain trick to get the address of
|
|
<code> <span class='ectt-1000'>kallsyms_lookup_name</span>
|
|
</code>. If <code> <span class='ectt-1000'>CONFIG_KPROBES</span>
|
|
</code> is enabled, we can facilitate the retrieval of function addresses by means of Kprobes
|
|
to dynamically break into the specific kernel routine. Kprobes inserts a breakpoint at
|
|
the entry of function by replacing the first bytes of the probed instruction. When a
|
|
CPU hits the breakpoint, registers are stored, and the control will pass to Kprobes. It
|
|
passes the addresses of the saved registers and the Kprobe struct to the handler
|
|
you defined, then executes it. Kprobes can be registered by symbol name
|
|
or address. Within the symbol name, the address will be handled by the
|
|
kernel.
|
|
</p><!-- l. 1257 --><p class='indent'> Otherwise, specify the address of <code> <span class='ectt-1000'>sys_call_table</span>
|
|
</code> from <span class='obeylines-h'><span class='verb'><span class='ectt-1000'>/proc/kallsyms</span></span></span> and <span class='obeylines-h'><span class='verb'><span class='ectt-1000'>/boot/System.map</span></span></span> into
|
|
<code> <span class='ectt-1000'>sym</span>
|
|
</code> parameter. Following is the sample usage for <span class='obeylines-h'><span class='verb'><span class='ectt-1000'>/proc/kallsyms</span></span></span>:
|
|
|
|
|
|
|
|
</p>
|
|
<pre class='verbatim' id='verbatim-12'>
|
|
$ sudo grep sys_call_table /proc/kallsyms
|
|
ffffffff82000280 R x32_sys_call_table
|
|
ffffffff820013a0 R sys_call_table
|
|
ffffffff820023e0 R ia32_sys_call_table
|
|
$ sudo insmod syscall.ko sym=0xffffffff820013a0
|
|
</pre>
|
|
<!-- l. 1265 --><p class='nopar'>
|
|
</p><!-- l. 1267 --><p class='indent'> Using the address from <span class='obeylines-h'><span class='verb'><span class='ectt-1000'>/boot/System.map</span></span></span>, be careful about <span class='obeylines-h'><span class='verb'><span class='ectt-1000'>KASLR</span></span></span> (Kernel
|
|
Address Space Layout Randomization). <span class='obeylines-h'><span class='verb'><span class='ectt-1000'>KASLR</span></span></span> may randomize the address of
|
|
kernel code and data at every boot time, such as the static address listed in
|
|
<span class='obeylines-h'><span class='verb'><span class='ectt-1000'>/boot/System.map</span></span></span> will offset by some entropy. The purpose of <span class='obeylines-h'><span class='verb'><span class='ectt-1000'>KASLR</span></span></span> is to protect
|
|
the kernel space from the attacker. Without <span class='obeylines-h'><span class='verb'><span class='ectt-1000'>KASLR</span></span></span>, the attacker may find the target
|
|
address in the fixed address easily. Then the attacker can use return-oriented
|
|
programming to insert some malicious codes to execute or receive the target data by
|
|
a tampered pointer. <span class='obeylines-h'><span class='verb'><span class='ectt-1000'>KASLR</span></span></span> mitigates these kinds of attacks because the attacker
|
|
cannot immediately know the target address, but a brute-force attack can still work.
|
|
If the address of a symbol in <span class='obeylines-h'><span class='verb'><span class='ectt-1000'>/proc/kallsyms</span></span></span> is different from the address in
|
|
<span class='obeylines-h'><span class='verb'><span class='ectt-1000'>/boot/System.map</span></span></span>, <span class='obeylines-h'><span class='verb'><span class='ectt-1000'>KASLR</span></span></span> is enabled with the kernel, which your system running
|
|
on.
|
|
|
|
|
|
|
|
</p>
|
|
<pre class='verbatim' id='verbatim-13'>
|
|
$ grep GRUB_CMDLINE_LINUX_DEFAULT /etc/default/grub
|
|
GRUB_CMDLINE_LINUX_DEFAULT="quiet splash"
|
|
$ sudo grep sys_call_table /boot/System.map-$(uname -r)
|
|
ffffffff82000300 R sys_call_table
|
|
$ sudo grep sys_call_table /proc/kallsyms
|
|
ffffffff820013a0 R sys_call_table
|
|
# Reboot
|
|
$ sudo grep sys_call_table /boot/System.map-$(uname -r)
|
|
ffffffff82000300 R sys_call_table
|
|
$ sudo grep sys_call_table /proc/kallsyms
|
|
ffffffff86400300 R sys_call_table
|
|
</pre>
|
|
<!-- l. 1286 --><p class='nopar'>If <span class='obeylines-h'><span class='verb'><span class='ectt-1000'>KASLR</span></span></span> is enabled, we have to take care of the address from <span class='obeylines-h'><span class='verb'><span class='ectt-1000'>/proc/kallsyms</span></span></span> each
|
|
time we reboot the machine. In order to use the address from <span class='obeylines-h'><span class='verb'><span class='ectt-1000'>/boot/System.map</span></span></span>,
|
|
make sure that <span class='obeylines-h'><span class='verb'><span class='ectt-1000'>KASLR</span></span></span> is disabled. You can add the <span class='obeylines-h'><span class='verb'><span class='ectt-1000'>nokaslr</span></span></span> for disabling <span class='obeylines-h'><span class='verb'><span class='ectt-1000'>KASLR</span></span></span> in
|
|
next booting time:
|
|
|
|
|
|
|
|
</p>
|
|
<pre class='verbatim' id='verbatim-14'>
|
|
$ grep GRUB_CMDLINE_LINUX_DEFAULT /etc/default/grub
|
|
GRUB_CMDLINE_LINUX_DEFAULT="quiet splash"
|
|
$ sudo perl -i -pe 'm/quiet/ and s//quiet nokaslr/' /etc/default/grub
|
|
$ grep quiet /etc/default/grub
|
|
GRUB_CMDLINE_LINUX_DEFAULT="quiet nokaslr splash"
|
|
$ sudo update-grub
|
|
</pre>
|
|
<!-- l. 1297 --><p class='nopar'>
|
|
</p><!-- l. 1299 --><p class='indent'> For more information, check out the following:
|
|
</p>
|
|
<ul class='itemize1'>
|
|
<li class='itemize'><a href='https://lwn.net/Articles/804849/'>Cook: Security things in Linux v5.3</a>
|
|
</li>
|
|
<li class='itemize'><a href='https://lwn.net/Articles/12211/'>Unexporting the system call table</a>
|
|
</li>
|
|
<li class='itemize'><a href='https://lwn.net/Articles/810077/'>Control-flow integrity for the kernel</a>
|
|
</li>
|
|
<li class='itemize'><a href='https://lwn.net/Articles/813350/'>Unexporting kallsyms_lookup_name()</a>
|
|
</li>
|
|
<li class='itemize'><a href='https://www.kernel.org/doc/Documentation/kprobes.txt'>Kernel Probes (Kprobes)</a>
|
|
</li>
|
|
<li class='itemize'><a href='https://lwn.net/Articles/569635/'>Kernel address space layout randomization</a></li></ul>
|
|
<!-- l. 1310 --><p class='indent'> The source code here is an example of such a kernel module. We want to “spy” on a certain
|
|
user, and to <code> <span class='ectt-1000'>pr_info()</span>
|
|
</code> a message whenever that user opens a file. Towards this end, we
|
|
replace the system call to open a file with our own function, called
|
|
<code> <span class='ectt-1000'>our_sys_open</span>
|
|
</code>. This function checks the uid (user’s id) of the current process, and if it is equal to the uid we
|
|
|
|
|
|
|
|
spy on, it calls <code> <span class='ectt-1000'>pr_info()</span>
|
|
</code> to display the name of the file to be opened. Then, either way, it calls the original
|
|
<code> <span class='ectt-1000'>open()</span>
|
|
</code> function with the same parameters, to actually open the file.
|
|
</p><!-- l. 1316 --><p class='indent'> The <code> <span class='ectt-1000'>init_module</span>
|
|
</code> function replaces the appropriate location in
|
|
<code> <span class='ectt-1000'>sys_call_table</span>
|
|
</code> and keeps the original pointer in a variable. The
|
|
<code> <span class='ectt-1000'>cleanup_module</span>
|
|
</code> function uses that variable to restore everything back to normal. This approach is
|
|
dangerous, because of the possibility of two kernel modules changing the same system
|
|
call. Imagine we have two kernel modules, A and B. A’s open system call will be
|
|
<code> <span class='ectt-1000'>A_open</span>
|
|
</code> and B’s will be <code> <span class='ectt-1000'>B_open</span>
|
|
</code>. Now, when A is inserted into the kernel, the system call is replaced with
|
|
<code> <span class='ectt-1000'>A_open</span>
|
|
</code>, which will call the original <code> <span class='ectt-1000'>sys_open</span>
|
|
</code> when it is done. Next, B is inserted into the kernel, which replaces the system call
|
|
with <code> <span class='ectt-1000'>B_open</span>
|
|
</code>, which will call what it thinks is the original system call,
|
|
<code> <span class='ectt-1000'>A_open</span>
|
|
</code>, when it’s done.
|
|
</p><!-- l. 1323 --><p class='indent'> Now, if B is removed first, everything will be well — it will simply restore the system
|
|
call to <code> <span class='ectt-1000'>A_open</span>
|
|
</code>, which calls the original. However, if A is removed and then B is removed, the
|
|
system will crash. A’s removal will restore the system call to the original,
|
|
<code> <span class='ectt-1000'>sys_open</span>
|
|
</code>, cutting B out of the loop. Then, when B is removed, it will restore the system call to what it thinks
|
|
is the original, <code> <span class='ectt-1000'>A_open</span>
|
|
</code>, which is no longer in memory. At first glance, it appears we could solve
|
|
this particular problem by checking if the system call is equal to our
|
|
open function and if so not changing it at all (so that B won’t change
|
|
the system call when it is removed), but that will cause an even worse
|
|
problem. When A is removed, it sees that the system call was changed to
|
|
<code> <span class='ectt-1000'>B_open</span>
|
|
</code> so that it is no longer pointing to <code> <span class='ectt-1000'>A_open</span>
|
|
</code>, so it will not restore it to <code> <span class='ectt-1000'>sys_open</span>
|
|
</code> before it is removed from memory. Unfortunately,
|
|
<code> <span class='ectt-1000'>B_open</span>
|
|
</code> will still try to call <code> <span class='ectt-1000'>A_open</span>
|
|
</code> which is no longer there, so that even without removing B the system would
|
|
crash.
|
|
</p><!-- l. 1331 --><p class='indent'> Note that all the related problems make syscall stealing unfeasible for
|
|
production use. In order to keep people from doing potential harmful things
|
|
<code> <span class='ectt-1000'>sys_call_table</span>
|
|
</code> is no longer exported. This means, if you want to do something more than a mere
|
|
|
|
|
|
|
|
dry run of this example, you will have to patch your current kernel in order to have
|
|
<code> <span class='ectt-1000'>sys_call_table</span>
|
|
</code> exported. In the example directory you will find a README and the patch. As you
|
|
can imagine, such modifications are not to be taken lightly. Do not try this on
|
|
valuable systems (ie systems that you do not own - or cannot restore easily). You will
|
|
need to get the complete sourcecode of this guide as a tarball in order to get the
|
|
patch and the README. Depending on your kernel version, you might even need to
|
|
hand apply the patch.
|
|
</p><!-- l. 1 --><p class='indent'>
|
|
</p>
|
|
<pre class='fancyvrb' id='fancyvrb52'><a id='x1-40044r1'></a><span class='ecrm-0500'>1</span><span id='textcolor1342'><span class='ectt-0800'>/*</span></span>
|
|
<a id='x1-40046r2'></a><span class='ecrm-0500'>2</span><span id='textcolor1343'><span class='ectt-0800'> * syscall.c</span></span>
|
|
<a id='x1-40048r3'></a><span class='ecrm-0500'>3</span><span id='textcolor1344'><span class='ectt-0800'> *</span></span>
|
|
<a id='x1-40050r4'></a><span class='ecrm-0500'>4</span><span id='textcolor1345'><span class='ectt-0800'> * System call "stealing" sample.</span></span>
|
|
<a id='x1-40052r5'></a><span class='ecrm-0500'>5</span><span id='textcolor1346'><span class='ectt-0800'> *</span></span>
|
|
<a id='x1-40054r6'></a><span class='ecrm-0500'>6</span><span id='textcolor1347'><span class='ectt-0800'> * Disables page protection at a processor level by changing the 16th bit</span></span>
|
|
<a id='x1-40056r7'></a><span class='ecrm-0500'>7</span><span id='textcolor1348'><span class='ectt-0800'> * in the cr0 register (could be Intel specific).</span></span>
|
|
<a id='x1-40058r8'></a><span class='ecrm-0500'>8</span><span id='textcolor1349'><span class='ectt-0800'> *</span></span>
|
|
<a id='x1-40060r9'></a><span class='ecrm-0500'>9</span><span id='textcolor1350'><span class='ectt-0800'> * Based on example by Peter Jay Salzman and</span></span>
|
|
<a id='x1-40062r10'></a><span class='ecrm-0500'>10</span><span id='textcolor1351'><span class='ectt-0800'> * https://bbs.archlinux.org/viewtopic.php?id=139406</span></span>
|
|
<a id='x1-40064r11'></a><span class='ecrm-0500'>11</span><span id='textcolor1352'><span class='ectt-0800'> */</span></span>
|
|
<a id='x1-40066r12'></a><span class='ecrm-0500'>12</span>
|
|
<a id='x1-40068r13'></a><span class='ecrm-0500'>13</span><span id='textcolor1353'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor1354'><span class='ectt-0800'><linux/delay.h></span></span>
|
|
<a id='x1-40070r14'></a><span class='ecrm-0500'>14</span><span id='textcolor1355'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor1356'><span class='ectt-0800'><linux/kernel.h></span></span>
|
|
<a id='x1-40072r15'></a><span class='ecrm-0500'>15</span><span id='textcolor1357'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor1358'><span class='ectt-0800'><linux/module.h></span></span>
|
|
<a id='x1-40074r16'></a><span class='ecrm-0500'>16</span><span id='textcolor1359'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor1360'><span class='ectt-0800'><linux/moduleparam.h> /* which will have params */</span></span>
|
|
<a id='x1-40076r17'></a><span class='ecrm-0500'>17</span><span id='textcolor1361'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor1362'><span class='ectt-0800'><linux/unistd.h> /* The list of system calls */</span></span>
|
|
<a id='x1-40078r18'></a><span class='ecrm-0500'>18</span><span id='textcolor1363'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor1364'><span class='ectt-0800'><linux/version.h></span></span>
|
|
<a id='x1-40080r19'></a><span class='ecrm-0500'>19</span>
|
|
<a id='x1-40082r20'></a><span class='ecrm-0500'>20</span><span id='textcolor1365'><span class='ectt-0800'>/* For the current (process) structure, we need this to know who the</span></span>
|
|
<a id='x1-40084r21'></a><span class='ecrm-0500'>21</span><span id='textcolor1366'><span class='ectt-0800'> * current user is.</span></span>
|
|
<a id='x1-40086r22'></a><span class='ecrm-0500'>22</span><span id='textcolor1367'><span class='ectt-0800'> */</span></span>
|
|
<a id='x1-40088r23'></a><span class='ecrm-0500'>23</span><span id='textcolor1368'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor1369'><span class='ectt-0800'><linux/sched.h></span></span>
|
|
<a id='x1-40090r24'></a><span class='ecrm-0500'>24</span><span id='textcolor1370'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor1371'><span class='ectt-0800'><linux/uaccess.h></span></span>
|
|
<a id='x1-40092r25'></a><span class='ecrm-0500'>25</span>
|
|
<a id='x1-40094r26'></a><span class='ecrm-0500'>26</span><span id='textcolor1372'><span class='ectt-0800'>/* The way we access "sys_call_table" varies as kernel internal changes.</span></span>
|
|
<a id='x1-40096r27'></a><span class='ecrm-0500'>27</span><span id='textcolor1373'><span class='ectt-0800'> * - ver <= 5.4 : manual symbol lookup</span></span>
|
|
<a id='x1-40098r28'></a><span class='ecrm-0500'>28</span><span id='textcolor1374'><span class='ectt-0800'> * - 5.4 < ver < 5.7 : kallsyms_lookup_name</span></span>
|
|
<a id='x1-40100r29'></a><span class='ecrm-0500'>29</span><span id='textcolor1375'><span class='ectt-0800'> * - 5.7 <= ver : Kprobes or specific kernel module parameter</span></span>
|
|
<a id='x1-40102r30'></a><span class='ecrm-0500'>30</span><span id='textcolor1376'><span class='ectt-0800'> */</span></span>
|
|
<a id='x1-40104r31'></a><span class='ecrm-0500'>31</span>
|
|
<a id='x1-40106r32'></a><span class='ecrm-0500'>32</span><span id='textcolor1377'><span class='ectt-0800'>/* The in-kernel calls to the ksys_close() syscall were removed in Linux v5.11+.</span></span>
|
|
<a id='x1-40108r33'></a><span class='ecrm-0500'>33</span><span id='textcolor1378'><span class='ectt-0800'> */</span></span>
|
|
<a id='x1-40110r34'></a><span class='ecrm-0500'>34</span><span id='textcolor1379'><span class='ectt-0800'>#if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 7, 0))</span></span>
|
|
<a id='x1-40112r35'></a><span class='ecrm-0500'>35</span>
|
|
<a id='x1-40114r36'></a><span class='ecrm-0500'>36</span><span id='textcolor1380'><span class='ectt-0800'>#if LINUX_VERSION_CODE <= KERNEL_VERSION(5, 4, 0)</span></span>
|
|
<a id='x1-40116r37'></a><span class='ecrm-0500'>37</span><span id='textcolor1381'><span class='ectt-0800'>#define HAVE_KSYS_CLOSE 1</span></span>
|
|
<a id='x1-40118r38'></a><span class='ecrm-0500'>38</span><span id='textcolor1382'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor1383'><span class='ectt-0800'><linux/syscalls.h> /* For ksys_close() */</span></span>
|
|
<a id='x1-40120r39'></a><span class='ecrm-0500'>39</span><span id='textcolor1384'><span class='ectt-0800'>#else</span></span>
|
|
<a id='x1-40122r40'></a><span class='ecrm-0500'>40</span><span id='textcolor1385'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor1386'><span class='ectt-0800'><linux/kallsyms.h> /* For kallsyms_lookup_name */</span></span>
|
|
<a id='x1-40124r41'></a><span class='ecrm-0500'>41</span><span id='textcolor1387'><span class='ectt-0800'>#endif</span></span>
|
|
<a id='x1-40126r42'></a><span class='ecrm-0500'>42</span>
|
|
<a id='x1-40128r43'></a><span class='ecrm-0500'>43</span><span id='textcolor1388'><span class='ectt-0800'>#else</span></span>
|
|
<a id='x1-40130r44'></a><span class='ecrm-0500'>44</span>
|
|
<a id='x1-40132r45'></a><span class='ecrm-0500'>45</span><span id='textcolor1389'><span class='ectt-0800'>#if defined(CONFIG_KPROBES)</span></span>
|
|
<a id='x1-40134r46'></a><span class='ecrm-0500'>46</span><span id='textcolor1390'><span class='ectt-0800'>#define HAVE_KPROBES 1</span></span>
|
|
<a id='x1-40136r47'></a><span class='ecrm-0500'>47</span><span id='textcolor1391'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor1392'><span class='ectt-0800'><linux/kprobes.h></span></span>
|
|
<a id='x1-40138r48'></a><span class='ecrm-0500'>48</span><span id='textcolor1393'><span class='ectt-0800'>#else</span></span>
|
|
<a id='x1-40140r49'></a><span class='ecrm-0500'>49</span><span id='textcolor1394'><span class='ectt-0800'>#define HAVE_PARAM 1</span></span>
|
|
<a id='x1-40142r50'></a><span class='ecrm-0500'>50</span><span id='textcolor1395'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor1396'><span class='ectt-0800'><linux/kallsyms.h> /* For sprint_symbol */</span></span>
|
|
<a id='x1-40144r51'></a><span class='ecrm-0500'>51</span><span id='textcolor1397'><span class='ectt-0800'>/* The address of the sys_call_table, which can be obtained with looking up</span></span>
|
|
<a id='x1-40146r52'></a><span class='ecrm-0500'>52</span><span id='textcolor1398'><span class='ectt-0800'> * "/boot/System.map" or "/proc/kallsyms". When the kernel version is v5.7+,</span></span>
|
|
<a id='x1-40148r53'></a><span class='ecrm-0500'>53</span><span id='textcolor1399'><span class='ectt-0800'> * without CONFIG_KPROBES, you can input the parameter or the module will look</span></span>
|
|
<a id='x1-40150r54'></a><span class='ecrm-0500'>54</span><span id='textcolor1400'><span class='ectt-0800'> * up all the memory.</span></span>
|
|
<a id='x1-40152r55'></a><span class='ecrm-0500'>55</span><span id='textcolor1401'><span class='ectt-0800'> */</span></span>
|
|
<a id='x1-40154r56'></a><span class='ecrm-0500'>56</span><span id='textcolor1402'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor1403'><span class='ectt-0800'>unsigned</span></span><span class='ectt-0800'> </span><span id='textcolor1404'><span class='ectt-0800'>long</span></span><span class='ectt-0800'> sym = 0;</span>
|
|
<a id='x1-40156r57'></a><span class='ecrm-0500'>57</span><span class='ectt-0800'>module_param(sym, ulong, 0644);</span>
|
|
<a id='x1-40158r58'></a><span class='ecrm-0500'>58</span><span id='textcolor1405'><span class='ectt-0800'>#endif </span></span><span id='textcolor1406'><span class='ectt-0800'>/* CONFIG_KPROBES */</span></span>
|
|
<a id='x1-40160r59'></a><span class='ecrm-0500'>59</span>
|
|
<a id='x1-40162r60'></a><span class='ecrm-0500'>60</span><span id='textcolor1407'><span class='ectt-0800'>#endif </span></span><span id='textcolor1408'><span class='ectt-0800'>/* Version < v5.7 */</span></span>
|
|
<a id='x1-40164r61'></a><span class='ecrm-0500'>61</span>
|
|
<a id='x1-40166r62'></a><span class='ecrm-0500'>62</span><span id='textcolor1409'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor1410'><span class='ectt-0800'>unsigned</span></span><span class='ectt-0800'> </span><span id='textcolor1411'><span class='ectt-0800'>long</span></span><span class='ectt-0800'> **sys_call_table;</span>
|
|
<a id='x1-40168r63'></a><span class='ecrm-0500'>63</span>
|
|
<a id='x1-40170r64'></a><span class='ecrm-0500'>64</span><span id='textcolor1412'><span class='ectt-0800'>/* UID we want to spy on - will be filled from the command line. */</span></span>
|
|
<a id='x1-40172r65'></a><span class='ecrm-0500'>65</span><span id='textcolor1413'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor1414'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> uid;</span>
|
|
<a id='x1-40174r66'></a><span class='ecrm-0500'>66</span><span class='ectt-0800'>module_param(uid, </span><span id='textcolor1415'><span class='ectt-0800'>int</span></span><span class='ectt-0800'>, 0644);</span>
|
|
<a id='x1-40176r67'></a><span class='ecrm-0500'>67</span>
|
|
<a id='x1-40178r68'></a><span class='ecrm-0500'>68</span><span id='textcolor1416'><span class='ectt-0800'>/* A pointer to the original system call. The reason we keep this, rather</span></span>
|
|
<a id='x1-40180r69'></a><span class='ecrm-0500'>69</span><span id='textcolor1417'><span class='ectt-0800'> * than call the original function (sys_open), is because somebody else</span></span>
|
|
<a id='x1-40182r70'></a><span class='ecrm-0500'>70</span><span id='textcolor1418'><span class='ectt-0800'> * might have replaced the system call before us. Note that this is not</span></span>
|
|
<a id='x1-40184r71'></a><span class='ecrm-0500'>71</span><span id='textcolor1419'><span class='ectt-0800'> * 100% safe, because if another module replaced sys_open before us,</span></span>
|
|
<a id='x1-40186r72'></a><span class='ecrm-0500'>72</span><span id='textcolor1420'><span class='ectt-0800'> * then when we are inserted, we will call the function in that module -</span></span>
|
|
<a id='x1-40188r73'></a><span class='ecrm-0500'>73</span><span id='textcolor1421'><span class='ectt-0800'> * and it might be removed before we are.</span></span>
|
|
<a id='x1-40190r74'></a><span class='ecrm-0500'>74</span><span id='textcolor1422'><span class='ectt-0800'> *</span></span>
|
|
<a id='x1-40192r75'></a><span class='ecrm-0500'>75</span><span id='textcolor1423'><span class='ectt-0800'> * Another reason for this is that we can not get sys_open.</span></span>
|
|
<a id='x1-40194r76'></a><span class='ecrm-0500'>76</span><span id='textcolor1424'><span class='ectt-0800'> * It is a static variable, so it is not exported.</span></span>
|
|
<a id='x1-40196r77'></a><span class='ecrm-0500'>77</span><span id='textcolor1425'><span class='ectt-0800'> */</span></span>
|
|
<a id='x1-40198r78'></a><span class='ecrm-0500'>78</span><span id='textcolor1426'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> asmlinkage int (*original_call)(</span><span id='textcolor1427'><span class='ectt-0800'>const</span></span><span class='ectt-0800'> </span><span id='textcolor1428'><span class='ectt-0800'>char</span></span><span class='ectt-0800'> *, </span><span id='textcolor1429'><span class='ectt-0800'>int</span></span><span class='ectt-0800'>, </span><span id='textcolor1430'><span class='ectt-0800'>int</span></span><span class='ectt-0800'>);</span>
|
|
<a id='x1-40200r79'></a><span class='ecrm-0500'>79</span>
|
|
<a id='x1-40202r80'></a><span class='ecrm-0500'>80</span><span id='textcolor1431'><span class='ectt-0800'>/* The function we will replace sys_open (the function called when you</span></span>
|
|
<a id='x1-40204r81'></a><span class='ecrm-0500'>81</span><span id='textcolor1432'><span class='ectt-0800'> * call the open system call) with. To find the exact prototype, with</span></span>
|
|
<a id='x1-40206r82'></a><span class='ecrm-0500'>82</span><span id='textcolor1433'><span class='ectt-0800'> * the number and type of arguments, we find the original function first</span></span>
|
|
<a id='x1-40208r83'></a><span class='ecrm-0500'>83</span><span id='textcolor1434'><span class='ectt-0800'> * (it is at fs/open.c).</span></span>
|
|
<a id='x1-40210r84'></a><span class='ecrm-0500'>84</span><span id='textcolor1435'><span class='ectt-0800'> *</span></span>
|
|
<a id='x1-40212r85'></a><span class='ecrm-0500'>85</span><span id='textcolor1436'><span class='ectt-0800'> * In theory, this means that we are tied to the current version of the</span></span>
|
|
<a id='x1-40214r86'></a><span class='ecrm-0500'>86</span><span id='textcolor1437'><span class='ectt-0800'> * kernel. In practice, the system calls almost never change (it would</span></span>
|
|
<a id='x1-40216r87'></a><span class='ecrm-0500'>87</span><span id='textcolor1438'><span class='ectt-0800'> * wreck havoc and require programs to be recompiled, since the system</span></span>
|
|
<a id='x1-40218r88'></a><span class='ecrm-0500'>88</span><span id='textcolor1439'><span class='ectt-0800'> * calls are the interface between the kernel and the processes).</span></span>
|
|
<a id='x1-40220r89'></a><span class='ecrm-0500'>89</span><span id='textcolor1440'><span class='ectt-0800'> */</span></span>
|
|
<a id='x1-40222r90'></a><span class='ecrm-0500'>90</span><span id='textcolor1441'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> asmlinkage </span><span id='textcolor1442'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> our_sys_open(</span><span id='textcolor1443'><span class='ectt-0800'>const</span></span><span class='ectt-0800'> </span><span id='textcolor1444'><span class='ectt-0800'>char</span></span><span class='ectt-0800'> *filename, </span><span id='textcolor1445'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> flags, </span><span id='textcolor1446'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> mode)</span>
|
|
<a id='x1-40224r91'></a><span class='ecrm-0500'>91</span><span class='ectt-0800'>{</span>
|
|
<a id='x1-40226r92'></a><span class='ecrm-0500'>92</span><span class='ectt-0800'> </span><span id='textcolor1447'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> i = 0;</span>
|
|
<a id='x1-40228r93'></a><span class='ecrm-0500'>93</span><span class='ectt-0800'> </span><span id='textcolor1448'><span class='ectt-0800'>char</span></span><span class='ectt-0800'> ch;</span>
|
|
<a id='x1-40230r94'></a><span class='ecrm-0500'>94</span>
|
|
<a id='x1-40232r95'></a><span class='ecrm-0500'>95</span><span class='ectt-0800'> </span><span id='textcolor1449'><span class='ectt-0800'>/* Report the file, if relevant */</span></span>
|
|
<a id='x1-40234r96'></a><span class='ecrm-0500'>96</span><span class='ectt-0800'> pr_info(</span><span id='textcolor1450'><span class='ectt-0800'>"Opened file by %d: "</span></span><span class='ectt-0800'>, uid);</span>
|
|
<a id='x1-40236r97'></a><span class='ecrm-0500'>97</span><span class='ectt-0800'> </span><span id='textcolor1451'><span class='ectt-0800'>do</span></span><span class='ectt-0800'> {</span>
|
|
<a id='x1-40238r98'></a><span class='ecrm-0500'>98</span><span class='ectt-0800'> get_user(ch, (</span><span id='textcolor1452'><span class='ectt-0800'>char</span></span><span class='ectt-0800'> __user *)filename + i);</span>
|
|
<a id='x1-40240r99'></a><span class='ecrm-0500'>99</span><span class='ectt-0800'> i++;</span>
|
|
<a id='x1-40242r100'></a><span class='ecrm-0500'>100</span><span class='ectt-0800'> pr_info(</span><span id='textcolor1453'><span class='ectt-0800'>"%c"</span></span><span class='ectt-0800'>, ch);</span>
|
|
<a id='x1-40244r101'></a><span class='ecrm-0500'>101</span><span class='ectt-0800'> } </span><span id='textcolor1454'><span class='ectt-0800'>while</span></span><span class='ectt-0800'> (ch != 0);</span>
|
|
<a id='x1-40246r102'></a><span class='ecrm-0500'>102</span><span class='ectt-0800'> pr_info(</span><span id='textcolor1455'><span class='ectt-0800'>"</span></span><span id='textcolor1456'><span class='ectt-0800'>\n</span></span><span id='textcolor1457'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>);</span>
|
|
<a id='x1-40248r103'></a><span class='ecrm-0500'>103</span>
|
|
<a id='x1-40250r104'></a><span class='ecrm-0500'>104</span><span class='ectt-0800'> </span><span id='textcolor1458'><span class='ectt-0800'>/* Call the original sys_open - otherwise, we lose the ability to</span></span>
|
|
<a id='x1-40252r105'></a><span class='ecrm-0500'>105</span><span id='textcolor1459'><span class='ectt-0800'> * open files.</span></span>
|
|
<a id='x1-40254r106'></a><span class='ecrm-0500'>106</span><span id='textcolor1460'><span class='ectt-0800'> */</span></span>
|
|
<a id='x1-40256r107'></a><span class='ecrm-0500'>107</span><span class='ectt-0800'> </span><span id='textcolor1461'><span class='ectt-0800'>return</span></span><span class='ectt-0800'> original_call(filename, flags, mode);</span>
|
|
<a id='x1-40258r108'></a><span class='ecrm-0500'>108</span><span class='ectt-0800'>}</span>
|
|
<a id='x1-40260r109'></a><span class='ecrm-0500'>109</span>
|
|
<a id='x1-40262r110'></a><span class='ecrm-0500'>110</span><span id='textcolor1462'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor1463'><span class='ectt-0800'>unsigned</span></span><span class='ectt-0800'> </span><span id='textcolor1464'><span class='ectt-0800'>long</span></span><span class='ectt-0800'> **aquire_sys_call_table(</span><span id='textcolor1465'><span class='ectt-0800'>void</span></span><span class='ectt-0800'>)</span>
|
|
<a id='x1-40264r111'></a><span class='ecrm-0500'>111</span><span class='ectt-0800'>{</span>
|
|
<a id='x1-40266r112'></a><span class='ecrm-0500'>112</span><span id='textcolor1466'><span class='ectt-0800'>#ifdef HAVE_KSYS_CLOSE</span></span>
|
|
<a id='x1-40268r113'></a><span class='ecrm-0500'>113</span><span class='ectt-0800'> </span><span id='textcolor1467'><span class='ectt-0800'>unsigned</span></span><span class='ectt-0800'> </span><span id='textcolor1468'><span class='ectt-0800'>long</span></span><span class='ectt-0800'> </span><span id='textcolor1469'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> offset = PAGE_OFFSET;</span>
|
|
<a id='x1-40270r114'></a><span class='ecrm-0500'>114</span><span class='ectt-0800'> </span><span id='textcolor1470'><span class='ectt-0800'>unsigned</span></span><span class='ectt-0800'> </span><span id='textcolor1471'><span class='ectt-0800'>long</span></span><span class='ectt-0800'> **sct;</span>
|
|
<a id='x1-40272r115'></a><span class='ecrm-0500'>115</span>
|
|
<a id='x1-40274r116'></a><span class='ecrm-0500'>116</span><span class='ectt-0800'> </span><span id='textcolor1472'><span class='ectt-0800'>while</span></span><span class='ectt-0800'> (offset < ULLONG_MAX) {</span>
|
|
<a id='x1-40276r117'></a><span class='ecrm-0500'>117</span><span class='ectt-0800'> sct = (</span><span id='textcolor1473'><span class='ectt-0800'>unsigned</span></span><span class='ectt-0800'> </span><span id='textcolor1474'><span class='ectt-0800'>long</span></span><span class='ectt-0800'> **)offset;</span>
|
|
<a id='x1-40278r118'></a><span class='ecrm-0500'>118</span>
|
|
<a id='x1-40280r119'></a><span class='ecrm-0500'>119</span><span class='ectt-0800'> </span><span id='textcolor1475'><span class='ectt-0800'>if</span></span><span class='ectt-0800'> (sct[__NR_close] == (</span><span id='textcolor1476'><span class='ectt-0800'>unsigned</span></span><span class='ectt-0800'> </span><span id='textcolor1477'><span class='ectt-0800'>long</span></span><span class='ectt-0800'> *)ksys_close)</span>
|
|
<a id='x1-40282r120'></a><span class='ecrm-0500'>120</span><span class='ectt-0800'> </span><span id='textcolor1478'><span class='ectt-0800'>return</span></span><span class='ectt-0800'> sct;</span>
|
|
<a id='x1-40284r121'></a><span class='ecrm-0500'>121</span>
|
|
<a id='x1-40286r122'></a><span class='ecrm-0500'>122</span><span class='ectt-0800'> offset += </span><span id='textcolor1479'><span class='ectt-0800'>sizeof</span></span><span class='ectt-0800'>(</span><span id='textcolor1480'><span class='ectt-0800'>void</span></span><span class='ectt-0800'> *);</span>
|
|
<a id='x1-40288r123'></a><span class='ecrm-0500'>123</span><span class='ectt-0800'> }</span>
|
|
<a id='x1-40290r124'></a><span class='ecrm-0500'>124</span>
|
|
<a id='x1-40292r125'></a><span class='ecrm-0500'>125</span><span class='ectt-0800'> </span><span id='textcolor1481'><span class='ectt-0800'>return</span></span><span class='ectt-0800'> NULL;</span>
|
|
<a id='x1-40294r126'></a><span class='ecrm-0500'>126</span><span id='textcolor1482'><span class='ectt-0800'>#endif</span></span>
|
|
<a id='x1-40296r127'></a><span class='ecrm-0500'>127</span>
|
|
<a id='x1-40298r128'></a><span class='ecrm-0500'>128</span><span id='textcolor1483'><span class='ectt-0800'>#ifdef HAVE_PARAM</span></span>
|
|
<a id='x1-40300r129'></a><span class='ecrm-0500'>129</span><span class='ectt-0800'> </span><span id='textcolor1484'><span class='ectt-0800'>const</span></span><span class='ectt-0800'> </span><span id='textcolor1485'><span class='ectt-0800'>char</span></span><span class='ectt-0800'> sct_name[15] = </span><span id='textcolor1486'><span class='ectt-0800'>"sys_call_table"</span></span><span class='ectt-0800'>;</span>
|
|
<a id='x1-40302r130'></a><span class='ecrm-0500'>130</span><span class='ectt-0800'> </span><span id='textcolor1487'><span class='ectt-0800'>char</span></span><span class='ectt-0800'> symbol[40] = { 0 };</span>
|
|
<a id='x1-40304r131'></a><span class='ecrm-0500'>131</span>
|
|
<a id='x1-40306r132'></a><span class='ecrm-0500'>132</span><span class='ectt-0800'> </span><span id='textcolor1488'><span class='ectt-0800'>if</span></span><span class='ectt-0800'> (sym == 0) {</span>
|
|
<a id='x1-40308r133'></a><span class='ecrm-0500'>133</span><span class='ectt-0800'> pr_alert(</span><span id='textcolor1489'><span class='ectt-0800'>"For Linux v5.7+, Kprobes is the preferable way to get "</span></span>
|
|
<a id='x1-40310r134'></a><span class='ecrm-0500'>134</span><span class='ectt-0800'> </span><span id='textcolor1490'><span class='ectt-0800'>"symbol.</span></span><span id='textcolor1491'><span class='ectt-0800'>\n</span></span><span id='textcolor1492'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>);</span>
|
|
<a id='x1-40312r135'></a><span class='ecrm-0500'>135</span><span class='ectt-0800'> pr_info(</span><span id='textcolor1493'><span class='ectt-0800'>"If Kprobes is absent, you have to specify the address of "</span></span>
|
|
<a id='x1-40314r136'></a><span class='ecrm-0500'>136</span><span class='ectt-0800'> </span><span id='textcolor1494'><span class='ectt-0800'>"sys_call_table symbol</span></span><span id='textcolor1495'><span class='ectt-0800'>\n</span></span><span id='textcolor1496'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>);</span>
|
|
<a id='x1-40316r137'></a><span class='ecrm-0500'>137</span><span class='ectt-0800'> pr_info(</span><span id='textcolor1497'><span class='ectt-0800'>"by /boot/System.map or /proc/kallsyms, which contains all the "</span></span>
|
|
<a id='x1-40318r138'></a><span class='ecrm-0500'>138</span><span class='ectt-0800'> </span><span id='textcolor1498'><span class='ectt-0800'>"symbol addresses, into sym parameter.</span></span><span id='textcolor1499'><span class='ectt-0800'>\n</span></span><span id='textcolor1500'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>);</span>
|
|
<a id='x1-40320r139'></a><span class='ecrm-0500'>139</span><span class='ectt-0800'> </span><span id='textcolor1501'><span class='ectt-0800'>return</span></span><span class='ectt-0800'> NULL;</span>
|
|
<a id='x1-40322r140'></a><span class='ecrm-0500'>140</span><span class='ectt-0800'> }</span>
|
|
<a id='x1-40324r141'></a><span class='ecrm-0500'>141</span><span class='ectt-0800'> sprint_symbol(symbol, sym);</span>
|
|
<a id='x1-40326r142'></a><span class='ecrm-0500'>142</span><span class='ectt-0800'> </span><span id='textcolor1502'><span class='ectt-0800'>if</span></span><span class='ectt-0800'> (!strncmp(sct_name, symbol, </span><span id='textcolor1503'><span class='ectt-0800'>sizeof</span></span><span class='ectt-0800'>(sct_name) - 1))</span>
|
|
<a id='x1-40328r143'></a><span class='ecrm-0500'>143</span><span class='ectt-0800'> </span><span id='textcolor1504'><span class='ectt-0800'>return</span></span><span class='ectt-0800'> (</span><span id='textcolor1505'><span class='ectt-0800'>unsigned</span></span><span class='ectt-0800'> </span><span id='textcolor1506'><span class='ectt-0800'>long</span></span><span class='ectt-0800'> **)sym;</span>
|
|
<a id='x1-40330r144'></a><span class='ecrm-0500'>144</span>
|
|
<a id='x1-40332r145'></a><span class='ecrm-0500'>145</span><span class='ectt-0800'> </span><span id='textcolor1507'><span class='ectt-0800'>return</span></span><span class='ectt-0800'> NULL;</span>
|
|
<a id='x1-40334r146'></a><span class='ecrm-0500'>146</span><span id='textcolor1508'><span class='ectt-0800'>#endif</span></span>
|
|
<a id='x1-40336r147'></a><span class='ecrm-0500'>147</span>
|
|
<a id='x1-40338r148'></a><span class='ecrm-0500'>148</span><span id='textcolor1509'><span class='ectt-0800'>#ifdef HAVE_KPROBES</span></span>
|
|
<a id='x1-40340r149'></a><span class='ecrm-0500'>149</span><span class='ectt-0800'> </span><span id='textcolor1510'><span class='ectt-0800'>unsigned</span></span><span class='ectt-0800'> </span><span id='textcolor1511'><span class='ectt-0800'>long</span></span><span class='ectt-0800'> (*kallsyms_lookup_name)(</span><span id='textcolor1512'><span class='ectt-0800'>const</span></span><span class='ectt-0800'> </span><span id='textcolor1513'><span class='ectt-0800'>char</span></span><span class='ectt-0800'> *name);</span>
|
|
<a id='x1-40342r150'></a><span class='ecrm-0500'>150</span><span class='ectt-0800'> </span><span id='textcolor1514'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> kprobe kp = {</span>
|
|
<a id='x1-40344r151'></a><span class='ecrm-0500'>151</span><span class='ectt-0800'> .symbol_name = </span><span id='textcolor1515'><span class='ectt-0800'>"kallsyms_lookup_name"</span></span><span class='ectt-0800'>,</span>
|
|
<a id='x1-40346r152'></a><span class='ecrm-0500'>152</span><span class='ectt-0800'> };</span>
|
|
<a id='x1-40348r153'></a><span class='ecrm-0500'>153</span>
|
|
<a id='x1-40350r154'></a><span class='ecrm-0500'>154</span><span class='ectt-0800'> </span><span id='textcolor1516'><span class='ectt-0800'>if</span></span><span class='ectt-0800'> (register_kprobe(&kp) < 0)</span>
|
|
<a id='x1-40352r155'></a><span class='ecrm-0500'>155</span><span class='ectt-0800'> </span><span id='textcolor1517'><span class='ectt-0800'>return</span></span><span class='ectt-0800'> NULL;</span>
|
|
<a id='x1-40354r156'></a><span class='ecrm-0500'>156</span><span class='ectt-0800'> kallsyms_lookup_name = (</span><span id='textcolor1518'><span class='ectt-0800'>unsigned</span></span><span class='ectt-0800'> </span><span id='textcolor1519'><span class='ectt-0800'>long</span></span><span class='ectt-0800'> (*)(</span><span id='textcolor1520'><span class='ectt-0800'>const</span></span><span class='ectt-0800'> </span><span id='textcolor1521'><span class='ectt-0800'>char</span></span><span class='ectt-0800'> *name))kp.addr;</span>
|
|
<a id='x1-40356r157'></a><span class='ecrm-0500'>157</span><span class='ectt-0800'> unregister_kprobe(&kp);</span>
|
|
<a id='x1-40358r158'></a><span class='ecrm-0500'>158</span><span id='textcolor1522'><span class='ectt-0800'>#endif</span></span>
|
|
<a id='x1-40360r159'></a><span class='ecrm-0500'>159</span>
|
|
<a id='x1-40362r160'></a><span class='ecrm-0500'>160</span><span class='ectt-0800'> </span><span id='textcolor1523'><span class='ectt-0800'>return</span></span><span class='ectt-0800'> (</span><span id='textcolor1524'><span class='ectt-0800'>unsigned</span></span><span class='ectt-0800'> </span><span id='textcolor1525'><span class='ectt-0800'>long</span></span><span class='ectt-0800'> **)kallsyms_lookup_name(</span><span id='textcolor1526'><span class='ectt-0800'>"sys_call_table"</span></span><span class='ectt-0800'>);</span>
|
|
<a id='x1-40364r161'></a><span class='ecrm-0500'>161</span><span class='ectt-0800'>}</span>
|
|
<a id='x1-40366r162'></a><span class='ecrm-0500'>162</span>
|
|
<a id='x1-40368r163'></a><span class='ecrm-0500'>163</span><span id='textcolor1527'><span class='ectt-0800'>#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0)</span></span>
|
|
<a id='x1-40370r164'></a><span class='ecrm-0500'>164</span><span id='textcolor1528'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor1529'><span class='ectt-0800'>inline</span></span><span class='ectt-0800'> </span><span id='textcolor1530'><span class='ectt-0800'>void</span></span><span class='ectt-0800'> __write_cr0(</span><span id='textcolor1531'><span class='ectt-0800'>unsigned</span></span><span class='ectt-0800'> </span><span id='textcolor1532'><span class='ectt-0800'>long</span></span><span class='ectt-0800'> cr0)</span>
|
|
<a id='x1-40372r165'></a><span class='ecrm-0500'>165</span><span class='ectt-0800'>{</span>
|
|
<a id='x1-40374r166'></a><span class='ecrm-0500'>166</span><span class='ectt-0800'> </span><span id='textcolor1533'><span class='ectt-0800'>asm</span></span><span class='ectt-0800'> </span><span id='textcolor1534'><span class='ectt-0800'>volatile</span></span><span class='ectt-0800'>(</span><span id='textcolor1535'><span class='ectt-0800'>"mov %0,%%cr0"</span></span><span class='ectt-0800'> : </span><span id='textcolor1536'><span class='ectt-0800'>"+r"</span></span><span class='ectt-0800'>(cr0) : : </span><span id='textcolor1537'><span class='ectt-0800'>"memory"</span></span><span class='ectt-0800'>);</span>
|
|
<a id='x1-40376r167'></a><span class='ecrm-0500'>167</span><span class='ectt-0800'>}</span>
|
|
<a id='x1-40378r168'></a><span class='ecrm-0500'>168</span><span id='textcolor1538'><span class='ectt-0800'>#else</span></span>
|
|
<a id='x1-40380r169'></a><span class='ecrm-0500'>169</span><span id='textcolor1539'><span class='ectt-0800'>#define __write_cr0 write_cr0</span></span>
|
|
<a id='x1-40382r170'></a><span class='ecrm-0500'>170</span><span id='textcolor1540'><span class='ectt-0800'>#endif</span></span>
|
|
<a id='x1-40384r171'></a><span class='ecrm-0500'>171</span>
|
|
<a id='x1-40386r172'></a><span class='ecrm-0500'>172</span><span id='textcolor1541'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor1542'><span class='ectt-0800'>void</span></span><span class='ectt-0800'> enable_write_protection(</span><span id='textcolor1543'><span class='ectt-0800'>void</span></span><span class='ectt-0800'>)</span>
|
|
<a id='x1-40388r173'></a><span class='ecrm-0500'>173</span><span class='ectt-0800'>{</span>
|
|
<a id='x1-40390r174'></a><span class='ecrm-0500'>174</span><span class='ectt-0800'> </span><span id='textcolor1544'><span class='ectt-0800'>unsigned</span></span><span class='ectt-0800'> </span><span id='textcolor1545'><span class='ectt-0800'>long</span></span><span class='ectt-0800'> cr0 = read_cr0();</span>
|
|
<a id='x1-40392r175'></a><span class='ecrm-0500'>175</span><span class='ectt-0800'> set_bit(16, &cr0);</span>
|
|
<a id='x1-40394r176'></a><span class='ecrm-0500'>176</span><span class='ectt-0800'> __write_cr0(cr0);</span>
|
|
<a id='x1-40396r177'></a><span class='ecrm-0500'>177</span><span class='ectt-0800'>}</span>
|
|
<a id='x1-40398r178'></a><span class='ecrm-0500'>178</span>
|
|
<a id='x1-40400r179'></a><span class='ecrm-0500'>179</span><span id='textcolor1546'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor1547'><span class='ectt-0800'>void</span></span><span class='ectt-0800'> disable_write_protection(</span><span id='textcolor1548'><span class='ectt-0800'>void</span></span><span class='ectt-0800'>)</span>
|
|
<a id='x1-40402r180'></a><span class='ecrm-0500'>180</span><span class='ectt-0800'>{</span>
|
|
<a id='x1-40404r181'></a><span class='ecrm-0500'>181</span><span class='ectt-0800'> </span><span id='textcolor1549'><span class='ectt-0800'>unsigned</span></span><span class='ectt-0800'> </span><span id='textcolor1550'><span class='ectt-0800'>long</span></span><span class='ectt-0800'> cr0 = read_cr0();</span>
|
|
<a id='x1-40406r182'></a><span class='ecrm-0500'>182</span><span class='ectt-0800'> clear_bit(16, &cr0);</span>
|
|
<a id='x1-40408r183'></a><span class='ecrm-0500'>183</span><span class='ectt-0800'> __write_cr0(cr0);</span>
|
|
<a id='x1-40410r184'></a><span class='ecrm-0500'>184</span><span class='ectt-0800'>}</span>
|
|
<a id='x1-40412r185'></a><span class='ecrm-0500'>185</span>
|
|
<a id='x1-40414r186'></a><span class='ecrm-0500'>186</span><span id='textcolor1551'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor1552'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> __init syscall_start(</span><span id='textcolor1553'><span class='ectt-0800'>void</span></span><span class='ectt-0800'>)</span>
|
|
<a id='x1-40416r187'></a><span class='ecrm-0500'>187</span><span class='ectt-0800'>{</span>
|
|
<a id='x1-40418r188'></a><span class='ecrm-0500'>188</span><span class='ectt-0800'> </span><span id='textcolor1554'><span class='ectt-0800'>if</span></span><span class='ectt-0800'> (!(sys_call_table = aquire_sys_call_table()))</span>
|
|
<a id='x1-40420r189'></a><span class='ecrm-0500'>189</span><span class='ectt-0800'> </span><span id='textcolor1555'><span class='ectt-0800'>return</span></span><span class='ectt-0800'> -1;</span>
|
|
<a id='x1-40422r190'></a><span class='ecrm-0500'>190</span>
|
|
<a id='x1-40424r191'></a><span class='ecrm-0500'>191</span><span class='ectt-0800'> disable_write_protection();</span>
|
|
<a id='x1-40426r192'></a><span class='ecrm-0500'>192</span>
|
|
<a id='x1-40428r193'></a><span class='ecrm-0500'>193</span><span class='ectt-0800'> </span><span id='textcolor1556'><span class='ectt-0800'>/* keep track of the original open function */</span></span>
|
|
<a id='x1-40430r194'></a><span class='ecrm-0500'>194</span><span class='ectt-0800'> original_call = (</span><span id='textcolor1557'><span class='ectt-0800'>void</span></span><span class='ectt-0800'> *)sys_call_table[__NR_open];</span>
|
|
<a id='x1-40432r195'></a><span class='ecrm-0500'>195</span>
|
|
<a id='x1-40434r196'></a><span class='ecrm-0500'>196</span><span class='ectt-0800'> </span><span id='textcolor1558'><span class='ectt-0800'>/* use our open function instead */</span></span>
|
|
<a id='x1-40436r197'></a><span class='ecrm-0500'>197</span><span class='ectt-0800'> sys_call_table[__NR_open] = (</span><span id='textcolor1559'><span class='ectt-0800'>unsigned</span></span><span class='ectt-0800'> </span><span id='textcolor1560'><span class='ectt-0800'>long</span></span><span class='ectt-0800'> *)our_sys_open;</span>
|
|
<a id='x1-40438r198'></a><span class='ecrm-0500'>198</span>
|
|
<a id='x1-40440r199'></a><span class='ecrm-0500'>199</span><span class='ectt-0800'> enable_write_protection();</span>
|
|
<a id='x1-40442r200'></a><span class='ecrm-0500'>200</span>
|
|
<a id='x1-40444r201'></a><span class='ecrm-0500'>201</span><span class='ectt-0800'> pr_info(</span><span id='textcolor1561'><span class='ectt-0800'>"Spying on UID:%d</span></span><span id='textcolor1562'><span class='ectt-0800'>\n</span></span><span id='textcolor1563'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>, uid);</span>
|
|
<a id='x1-40446r202'></a><span class='ecrm-0500'>202</span>
|
|
<a id='x1-40448r203'></a><span class='ecrm-0500'>203</span><span class='ectt-0800'> </span><span id='textcolor1564'><span class='ectt-0800'>return</span></span><span class='ectt-0800'> 0;</span>
|
|
<a id='x1-40450r204'></a><span class='ecrm-0500'>204</span><span class='ectt-0800'>}</span>
|
|
<a id='x1-40452r205'></a><span class='ecrm-0500'>205</span>
|
|
<a id='x1-40454r206'></a><span class='ecrm-0500'>206</span><span id='textcolor1565'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor1566'><span class='ectt-0800'>void</span></span><span class='ectt-0800'> __exit syscall_end(</span><span id='textcolor1567'><span class='ectt-0800'>void</span></span><span class='ectt-0800'>)</span>
|
|
<a id='x1-40456r207'></a><span class='ecrm-0500'>207</span><span class='ectt-0800'>{</span>
|
|
<a id='x1-40458r208'></a><span class='ecrm-0500'>208</span><span class='ectt-0800'> </span><span id='textcolor1568'><span class='ectt-0800'>if</span></span><span class='ectt-0800'> (!sys_call_table)</span>
|
|
<a id='x1-40460r209'></a><span class='ecrm-0500'>209</span><span class='ectt-0800'> </span><span id='textcolor1569'><span class='ectt-0800'>return</span></span><span class='ectt-0800'>;</span>
|
|
<a id='x1-40462r210'></a><span class='ecrm-0500'>210</span>
|
|
<a id='x1-40464r211'></a><span class='ecrm-0500'>211</span><span class='ectt-0800'> </span><span id='textcolor1570'><span class='ectt-0800'>/* Return the system call back to normal */</span></span>
|
|
<a id='x1-40466r212'></a><span class='ecrm-0500'>212</span><span class='ectt-0800'> </span><span id='textcolor1571'><span class='ectt-0800'>if</span></span><span class='ectt-0800'> (sys_call_table[__NR_open] != (</span><span id='textcolor1572'><span class='ectt-0800'>unsigned</span></span><span class='ectt-0800'> </span><span id='textcolor1573'><span class='ectt-0800'>long</span></span><span class='ectt-0800'> *)our_sys_open) {</span>
|
|
<a id='x1-40468r213'></a><span class='ecrm-0500'>213</span><span class='ectt-0800'> pr_alert(</span><span id='textcolor1574'><span class='ectt-0800'>"Somebody else also played with the "</span></span><span class='ectt-0800'>);</span>
|
|
<a id='x1-40470r214'></a><span class='ecrm-0500'>214</span><span class='ectt-0800'> pr_alert(</span><span id='textcolor1575'><span class='ectt-0800'>"open system call</span></span><span id='textcolor1576'><span class='ectt-0800'>\n</span></span><span id='textcolor1577'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>);</span>
|
|
<a id='x1-40472r215'></a><span class='ecrm-0500'>215</span><span class='ectt-0800'> pr_alert(</span><span id='textcolor1578'><span class='ectt-0800'>"The system may be left in "</span></span><span class='ectt-0800'>);</span>
|
|
<a id='x1-40474r216'></a><span class='ecrm-0500'>216</span><span class='ectt-0800'> pr_alert(</span><span id='textcolor1579'><span class='ectt-0800'>"an unstable state.</span></span><span id='textcolor1580'><span class='ectt-0800'>\n</span></span><span id='textcolor1581'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>);</span>
|
|
<a id='x1-40476r217'></a><span class='ecrm-0500'>217</span><span class='ectt-0800'> }</span>
|
|
<a id='x1-40478r218'></a><span class='ecrm-0500'>218</span>
|
|
<a id='x1-40480r219'></a><span class='ecrm-0500'>219</span><span class='ectt-0800'> disable_write_protection();</span>
|
|
<a id='x1-40482r220'></a><span class='ecrm-0500'>220</span><span class='ectt-0800'> sys_call_table[__NR_open] = (</span><span id='textcolor1582'><span class='ectt-0800'>unsigned</span></span><span class='ectt-0800'> </span><span id='textcolor1583'><span class='ectt-0800'>long</span></span><span class='ectt-0800'> *)original_call;</span>
|
|
<a id='x1-40484r221'></a><span class='ecrm-0500'>221</span><span class='ectt-0800'> enable_write_protection();</span>
|
|
<a id='x1-40486r222'></a><span class='ecrm-0500'>222</span>
|
|
<a id='x1-40488r223'></a><span class='ecrm-0500'>223</span><span class='ectt-0800'> msleep(2000);</span>
|
|
<a id='x1-40490r224'></a><span class='ecrm-0500'>224</span><span class='ectt-0800'>}</span>
|
|
<a id='x1-40492r225'></a><span class='ecrm-0500'>225</span>
|
|
<a id='x1-40494r226'></a><span class='ecrm-0500'>226</span><span class='ectt-0800'>module_init(syscall_start);</span>
|
|
<a id='x1-40496r227'></a><span class='ecrm-0500'>227</span><span class='ectt-0800'>module_exit(syscall_end);</span>
|
|
<a id='x1-40498r228'></a><span class='ecrm-0500'>228</span>
|
|
<a id='x1-40500r229'></a><span class='ecrm-0500'>229</span><span class='ectt-0800'>MODULE_LICENSE(</span><span id='textcolor1584'><span class='ectt-0800'>"GPL"</span></span><span class='ectt-0800'>);</span></pre>
|
|
<!-- l. 1342 --><p class='noindent'>
|
|
</p>
|
|
<h3 class='sectionHead' id='blocking-processes-and-threads'><span class='titlemark'>11 </span> <a id='x1-4100011'></a>Blocking Processes and threads</h3>
|
|
<!-- l. 1344 --><p class='noindent'>
|
|
</p>
|
|
<h4 class='subsectionHead' id='sleep'><span class='titlemark'>11.1 </span> <a id='x1-4200011.1'></a>Sleep</h4>
|
|
<!-- l. 1346 --><p class='noindent'>What do you do when somebody asks you for something you can not do right
|
|
away? If you are a human being and you are bothered by a human being, the
|
|
only thing you can say is: "<span class='ecti-1000'>Not right now, I’m busy. Go away!</span>". But if you
|
|
are a kernel module and you are bothered by a process, you have another
|
|
possibility. You can put the process to sleep until you can service it. After all,
|
|
processes are being put to sleep by the kernel and woken up all the time (that
|
|
is the way multiple processes appear to run on the same time on a single
|
|
CPU).
|
|
</p><!-- l. 1352 --><p class='indent'> This kernel module is an example of this. The file (called <span class='obeylines-h'><span class='verb'><span class='ectt-1000'>/proc/sleep</span></span></span>) can only
|
|
be opened by a single process at a time. If the file is already open, the kernel module
|
|
calls <code> <span class='ectt-1000'>wait_event_interruptible</span>
|
|
</code>. The easiest way to keep a file open is to open it with:
|
|
</p><!-- l. 1 --><p class='indent'>
|
|
</p>
|
|
<pre class='fancyvrb' id='fancyvrb53'><a id='x1-42004r1'></a><span class='ecrm-0500'>1</span><span class='ectt-1000'>tail -f</span></pre>
|
|
<!-- l. 1361 --><p class='indent'> This function changes the status of the task (a task is the kernel data structure
|
|
which holds information about a process and the system call it is in, if any) to
|
|
<code> <span class='ectt-1000'>TASK_INTERRUPTIBLE</span>
|
|
</code>, which means that the task will not run until it is woken up somehow, and adds it to
|
|
WaitQ, the queue of tasks waiting to access the file. Then, the function calls the
|
|
scheduler to context switch to a different process, one which has some use for the
|
|
CPU.
|
|
|
|
|
|
|
|
</p><!-- l. 1365 --><p class='indent'> When a process is done with the file, it closes it, and
|
|
<code> <span class='ectt-1000'>module_close</span>
|
|
</code> is called. That function wakes up all the processes in the queue (there’s no
|
|
mechanism to only wake up one of them). It then returns and the process which just
|
|
closed the file can continue to run. In time, the scheduler decides that that
|
|
process has had enough and gives control of the CPU to another process.
|
|
Eventually, one of the processes which was in the queue will be given control
|
|
of the CPU by the scheduler. It starts at the point right after the call to
|
|
<code> <span class='ectt-1000'>module_interruptible_sleep_on</span>
|
|
</code>.
|
|
</p><!-- l. 1372 --><p class='indent'> This means that the process is still in kernel mode - as far as the process
|
|
is concerned, it issued the open system call and the system call has not
|
|
returned yet. The process does not know somebody else used the CPU for
|
|
most of the time between the moment it issued the call and the moment it
|
|
returned.
|
|
</p><!-- l. 1375 --><p class='indent'> It can then proceed to set a global variable to tell all the other processes that the
|
|
file is still open and go on with its life. When the other processes get a piece of the
|
|
CPU, they’ll see that global variable and go back to sleep.
|
|
</p><!-- l. 1378 --><p class='indent'> So we will use <code> <span class='ectt-1000'>tail -f</span>
|
|
</code> to keep the file open in the background, while trying to access it with another
|
|
process (again in the background, so that we need not switch to a different vt). As
|
|
soon as the first background process is killed with kill %1 , the second is woken up, is
|
|
able to access the file and finally terminates.
|
|
</p><!-- l. 1381 --><p class='indent'> To make our life more interesting, <code> <span class='ectt-1000'>module_close</span>
|
|
</code> does not have a monopoly on waking up the processes which wait to access the file.
|
|
A signal, such as <span class='ecti-1000'>Ctrl +c </span>(<span class='ecbx-1000'>SIGINT</span>) can also wake up a process. This is because we
|
|
used <code> <span class='ectt-1000'>module_interruptible_sleep_on</span>
|
|
</code>. We could have used <code> <span class='ectt-1000'>module_sleep_on</span>
|
|
</code> instead, but that would have resulted in extremely angry users whose <span class='ecti-1000'>Ctrl+c</span>’s are
|
|
ignored.
|
|
</p><!-- l. 1385 --><p class='indent'> In that case, we want to return with
|
|
<code> <span class='ectt-1000'>-EINTR</span>
|
|
</code> immediately. This is important so users can, for example, kill the process before it
|
|
receives the file.
|
|
</p><!-- l. 1387 --><p class='indent'> There is one more point to remember. Some times processes don’t want to sleep, they want
|
|
either to get what they want immediately, or to be told it cannot be done. Such processes
|
|
use the <code> <span class='ectt-1000'>O_NONBLOCK</span>
|
|
</code> flag when opening the file. The kernel is supposed to respond by returning with the error
|
|
code <code> <span class='ectt-1000'>-EAGAIN</span>
|
|
</code> from operations which would otherwise block, such as opening the file in this example. The
|
|
program <code> <span class='ectt-1000'>cat_nonblock</span>
|
|
</code>, available in the <span class='obeylines-h'><span class='verb'><span class='ectt-1000'>examples/other</span></span></span> directory, can be used to open a file with
|
|
<code> <span class='ectt-1000'>O_NONBLOCK</span>
|
|
</code>.
|
|
|
|
|
|
|
|
</p>
|
|
<pre class='verbatim' id='verbatim-15'>
|
|
$ sudo insmod sleep.ko
|
|
$ cat_nonblock /proc/sleep
|
|
Last input:
|
|
$ tail -f /proc/sleep &
|
|
Last input:
|
|
Last input:
|
|
Last input:
|
|
Last input:
|
|
Last input:
|
|
Last input:
|
|
Last input:
|
|
tail: /proc/sleep: file truncated
|
|
[1] 6540
|
|
$ cat_nonblock /proc/sleep
|
|
Open would block
|
|
$ kill %1
|
|
[1]+ Terminated tail -f /proc/sleep
|
|
$ cat_nonblock /proc/sleep
|
|
Last input:
|
|
$
|
|
</pre>
|
|
<!-- l. 1412 --><p class='nopar'>
|
|
</p><!-- l. 1 --><p class='indent'>
|
|
</p>
|
|
<pre class='fancyvrb' id='fancyvrb54'><a id='x1-42018r1'></a><span class='ecrm-0500'>1</span><span id='textcolor1585'><span class='ectt-0800'>/*</span></span>
|
|
<a id='x1-42020r2'></a><span class='ecrm-0500'>2</span><span id='textcolor1586'><span class='ectt-0800'> * sleep.c - create a /proc file, and if several processes try to open it</span></span>
|
|
<a id='x1-42022r3'></a><span class='ecrm-0500'>3</span><span id='textcolor1587'><span class='ectt-0800'> * at the same time, put all but one to sleep.</span></span>
|
|
<a id='x1-42024r4'></a><span class='ecrm-0500'>4</span><span id='textcolor1588'><span class='ectt-0800'> */</span></span>
|
|
<a id='x1-42026r5'></a><span class='ecrm-0500'>5</span>
|
|
<a id='x1-42028r6'></a><span class='ecrm-0500'>6</span><span id='textcolor1589'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor1590'><span class='ectt-0800'><linux/kernel.h> /* We</span><span class='tctt-0800'>'</span><span class='ectt-0800'>re doing kernel work */</span></span>
|
|
<a id='x1-42030r7'></a><span class='ecrm-0500'>7</span><span id='textcolor1591'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor1592'><span class='ectt-0800'><linux/module.h> /* Specifically, a module */</span></span>
|
|
<a id='x1-42032r8'></a><span class='ecrm-0500'>8</span><span id='textcolor1593'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor1594'><span class='ectt-0800'><linux/proc_fs.h> /* Necessary because we use proc fs */</span></span>
|
|
<a id='x1-42034r9'></a><span class='ecrm-0500'>9</span><span id='textcolor1595'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor1596'><span class='ectt-0800'><linux/sched.h> /* For putting processes to sleep and</span></span>
|
|
<a id='x1-42036r10'></a><span class='ecrm-0500'>10</span><span class='ectt-0800'> waking them up </span><span class='colorbox' id='colorbox1597'><span class='ectt-0800'>*/</span></span>
|
|
<a id='x1-42038r11'></a><span class='ecrm-0500'>11</span><span id='textcolor1598'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor1599'><span class='ectt-0800'><linux/uaccess.h> /* for get_user and put_user */</span></span>
|
|
<a id='x1-42040r12'></a><span class='ecrm-0500'>12</span><span id='textcolor1600'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor1601'><span class='ectt-0800'><linux/version.h></span></span>
|
|
<a id='x1-42042r13'></a><span class='ecrm-0500'>13</span>
|
|
<a id='x1-42044r14'></a><span class='ecrm-0500'>14</span><span id='textcolor1602'><span class='ectt-0800'>#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 6, 0)</span></span>
|
|
<a id='x1-42046r15'></a><span class='ecrm-0500'>15</span><span id='textcolor1603'><span class='ectt-0800'>#define HAVE_PROC_OPS</span></span>
|
|
<a id='x1-42048r16'></a><span class='ecrm-0500'>16</span><span id='textcolor1604'><span class='ectt-0800'>#endif</span></span>
|
|
<a id='x1-42050r17'></a><span class='ecrm-0500'>17</span>
|
|
<a id='x1-42052r18'></a><span class='ecrm-0500'>18</span><span id='textcolor1605'><span class='ectt-0800'>/* Here we keep the last message received, to prove that we can process our</span></span>
|
|
<a id='x1-42054r19'></a><span class='ecrm-0500'>19</span><span id='textcolor1606'><span class='ectt-0800'> * input.</span></span>
|
|
<a id='x1-42056r20'></a><span class='ecrm-0500'>20</span><span id='textcolor1607'><span class='ectt-0800'> */</span></span>
|
|
<a id='x1-42058r21'></a><span class='ecrm-0500'>21</span><span id='textcolor1608'><span class='ectt-0800'>#define MESSAGE_LENGTH 80</span></span>
|
|
<a id='x1-42060r22'></a><span class='ecrm-0500'>22</span><span id='textcolor1609'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor1610'><span class='ectt-0800'>char</span></span><span class='ectt-0800'> message[MESSAGE_LENGTH];</span>
|
|
<a id='x1-42062r23'></a><span class='ecrm-0500'>23</span>
|
|
<a id='x1-42064r24'></a><span class='ecrm-0500'>24</span><span id='textcolor1611'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor1612'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> proc_dir_entry *our_proc_file;</span>
|
|
<a id='x1-42066r25'></a><span class='ecrm-0500'>25</span><span id='textcolor1613'><span class='ectt-0800'>#define PROC_ENTRY_FILENAME "sleep"</span></span>
|
|
<a id='x1-42068r26'></a><span class='ecrm-0500'>26</span>
|
|
<a id='x1-42070r27'></a><span class='ecrm-0500'>27</span><span id='textcolor1614'><span class='ectt-0800'>/* Since we use the file operations struct, we can</span><span class='tctt-0800'>'</span><span class='ectt-0800'>t use the special proc</span></span>
|
|
<a id='x1-42072r28'></a><span class='ecrm-0500'>28</span><span id='textcolor1615'><span class='ectt-0800'> * output provisions - we have to use a standard read function, which is this</span></span>
|
|
<a id='x1-42074r29'></a><span class='ecrm-0500'>29</span><span id='textcolor1616'><span class='ectt-0800'> * function.</span></span>
|
|
<a id='x1-42076r30'></a><span class='ecrm-0500'>30</span><span id='textcolor1617'><span class='ectt-0800'> */</span></span>
|
|
<a id='x1-42078r31'></a><span class='ecrm-0500'>31</span><span id='textcolor1618'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor1619'><span class='ectt-0800'>ssize_t</span></span><span class='ectt-0800'> module_output(</span><span id='textcolor1620'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> file *file, </span><span id='textcolor1621'><span class='ectt-0800'>/* see include/linux/fs.h */</span></span>
|
|
<a id='x1-42080r32'></a><span class='ecrm-0500'>32</span><span class='ectt-0800'> </span><span id='textcolor1622'><span class='ectt-0800'>char</span></span><span class='ectt-0800'> __user *buf, </span><span id='textcolor1623'><span class='ectt-0800'>/* The buffer to put data to</span></span>
|
|
<a id='x1-42082r33'></a><span class='ecrm-0500'>33</span><span id='textcolor1624'><span class='ectt-0800'> (in the user segment)</span></span><span class='ectt-0800'> </span><span class='colorbox' id='colorbox1625'><span class='ectt-0800'>*/</span></span>
|
|
<a id='x1-42084r34'></a><span class='ecrm-0500'>34</span><span class='ectt-0800'> </span><span id='textcolor1626'><span class='ectt-0800'>size_t</span></span><span class='ectt-0800'> len, </span><span id='textcolor1627'><span class='ectt-0800'>/* The length of the buffer */</span></span>
|
|
<a id='x1-42086r35'></a><span class='ecrm-0500'>35</span><span class='ectt-0800'> loff_t *offset)</span>
|
|
<a id='x1-42088r36'></a><span class='ecrm-0500'>36</span><span class='ectt-0800'>{</span>
|
|
<a id='x1-42090r37'></a><span class='ecrm-0500'>37</span><span class='ectt-0800'> </span><span id='textcolor1628'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor1629'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> finished = 0;</span>
|
|
<a id='x1-42092r38'></a><span class='ecrm-0500'>38</span><span class='ectt-0800'> </span><span id='textcolor1630'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> i;</span>
|
|
<a id='x1-42094r39'></a><span class='ecrm-0500'>39</span><span class='ectt-0800'> </span><span id='textcolor1631'><span class='ectt-0800'>char</span></span><span class='ectt-0800'> output_msg[MESSAGE_LENGTH + 30];</span>
|
|
<a id='x1-42096r40'></a><span class='ecrm-0500'>40</span>
|
|
<a id='x1-42098r41'></a><span class='ecrm-0500'>41</span><span class='ectt-0800'> </span><span id='textcolor1632'><span class='ectt-0800'>/* Return 0 to signify end of file - that we have nothing more to say</span></span>
|
|
<a id='x1-42100r42'></a><span class='ecrm-0500'>42</span><span id='textcolor1633'><span class='ectt-0800'> * at this point.</span></span>
|
|
<a id='x1-42102r43'></a><span class='ecrm-0500'>43</span><span id='textcolor1634'><span class='ectt-0800'> */</span></span>
|
|
<a id='x1-42104r44'></a><span class='ecrm-0500'>44</span><span class='ectt-0800'> </span><span id='textcolor1635'><span class='ectt-0800'>if</span></span><span class='ectt-0800'> (finished) {</span>
|
|
<a id='x1-42106r45'></a><span class='ecrm-0500'>45</span><span class='ectt-0800'> finished = 0;</span>
|
|
<a id='x1-42108r46'></a><span class='ecrm-0500'>46</span><span class='ectt-0800'> </span><span id='textcolor1636'><span class='ectt-0800'>return</span></span><span class='ectt-0800'> 0;</span>
|
|
<a id='x1-42110r47'></a><span class='ecrm-0500'>47</span><span class='ectt-0800'> }</span>
|
|
<a id='x1-42112r48'></a><span class='ecrm-0500'>48</span>
|
|
<a id='x1-42114r49'></a><span class='ecrm-0500'>49</span><span class='ectt-0800'> sprintf(output_msg, </span><span id='textcolor1637'><span class='ectt-0800'>"Last input:%s</span></span><span id='textcolor1638'><span class='ectt-0800'>\n</span></span><span id='textcolor1639'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>, message);</span>
|
|
<a id='x1-42116r50'></a><span class='ecrm-0500'>50</span><span class='ectt-0800'> </span><span id='textcolor1640'><span class='ectt-0800'>for</span></span><span class='ectt-0800'> (i = 0; i < len && output_msg[i]; i++)</span>
|
|
<a id='x1-42118r51'></a><span class='ecrm-0500'>51</span><span class='ectt-0800'> put_user(output_msg[i], buf + i);</span>
|
|
<a id='x1-42120r52'></a><span class='ecrm-0500'>52</span>
|
|
<a id='x1-42122r53'></a><span class='ecrm-0500'>53</span><span class='ectt-0800'> finished = 1;</span>
|
|
<a id='x1-42124r54'></a><span class='ecrm-0500'>54</span><span class='ectt-0800'> </span><span id='textcolor1641'><span class='ectt-0800'>return</span></span><span class='ectt-0800'> i; </span><span id='textcolor1642'><span class='ectt-0800'>/* Return the number of bytes "read" */</span></span>
|
|
<a id='x1-42126r55'></a><span class='ecrm-0500'>55</span><span class='ectt-0800'>}</span>
|
|
<a id='x1-42128r56'></a><span class='ecrm-0500'>56</span>
|
|
<a id='x1-42130r57'></a><span class='ecrm-0500'>57</span><span id='textcolor1643'><span class='ectt-0800'>/* This function receives input from the user when the user writes to the</span></span>
|
|
<a id='x1-42132r58'></a><span class='ecrm-0500'>58</span><span id='textcolor1644'><span class='ectt-0800'> * /proc file.</span></span>
|
|
<a id='x1-42134r59'></a><span class='ecrm-0500'>59</span><span id='textcolor1645'><span class='ectt-0800'> */</span></span>
|
|
<a id='x1-42136r60'></a><span class='ecrm-0500'>60</span><span id='textcolor1646'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor1647'><span class='ectt-0800'>ssize_t</span></span><span class='ectt-0800'> module_input(</span><span id='textcolor1648'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> file *file, </span><span id='textcolor1649'><span class='ectt-0800'>/* The file itself */</span></span>
|
|
<a id='x1-42138r61'></a><span class='ecrm-0500'>61</span><span class='ectt-0800'> </span><span id='textcolor1650'><span class='ectt-0800'>const</span></span><span class='ectt-0800'> </span><span id='textcolor1651'><span class='ectt-0800'>char</span></span><span class='ectt-0800'> __user *buf, </span><span id='textcolor1652'><span class='ectt-0800'>/* The buffer with input */</span></span>
|
|
<a id='x1-42140r62'></a><span class='ecrm-0500'>62</span><span class='ectt-0800'> </span><span id='textcolor1653'><span class='ectt-0800'>size_t</span></span><span class='ectt-0800'> length, </span><span id='textcolor1654'><span class='ectt-0800'>/* The buffer</span><span class='tctt-0800'>'</span><span class='ectt-0800'>s length */</span></span>
|
|
<a id='x1-42142r63'></a><span class='ecrm-0500'>63</span><span class='ectt-0800'> loff_t *offset) </span><span id='textcolor1655'><span class='ectt-0800'>/* offset to file - ignore */</span></span>
|
|
<a id='x1-42144r64'></a><span class='ecrm-0500'>64</span><span class='ectt-0800'>{</span>
|
|
<a id='x1-42146r65'></a><span class='ecrm-0500'>65</span><span class='ectt-0800'> </span><span id='textcolor1656'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> i;</span>
|
|
<a id='x1-42148r66'></a><span class='ecrm-0500'>66</span>
|
|
<a id='x1-42150r67'></a><span class='ecrm-0500'>67</span><span class='ectt-0800'> </span><span id='textcolor1657'><span class='ectt-0800'>/* Put the input into Message, where module_output will later be able</span></span>
|
|
<a id='x1-42152r68'></a><span class='ecrm-0500'>68</span><span id='textcolor1658'><span class='ectt-0800'> * to use it.</span></span>
|
|
<a id='x1-42154r69'></a><span class='ecrm-0500'>69</span><span id='textcolor1659'><span class='ectt-0800'> */</span></span>
|
|
<a id='x1-42156r70'></a><span class='ecrm-0500'>70</span><span class='ectt-0800'> </span><span id='textcolor1660'><span class='ectt-0800'>for</span></span><span class='ectt-0800'> (i = 0; i < MESSAGE_LENGTH - 1 && i < length; i++)</span>
|
|
<a id='x1-42158r71'></a><span class='ecrm-0500'>71</span><span class='ectt-0800'> get_user(message[i], buf + i);</span>
|
|
<a id='x1-42160r72'></a><span class='ecrm-0500'>72</span><span class='ectt-0800'> </span><span id='textcolor1661'><span class='ectt-0800'>/* we want a standard, zero terminated string */</span></span>
|
|
<a id='x1-42162r73'></a><span class='ecrm-0500'>73</span><span class='ectt-0800'> message[i] = </span><span id='textcolor1662'><span class='tctt-0800'>'</span><span class='ectt-0800'>\0</span><span class='tctt-0800'>'</span></span><span class='ectt-0800'>;</span>
|
|
<a id='x1-42164r74'></a><span class='ecrm-0500'>74</span>
|
|
<a id='x1-42166r75'></a><span class='ecrm-0500'>75</span><span class='ectt-0800'> </span><span id='textcolor1663'><span class='ectt-0800'>/* We need to return the number of input characters used */</span></span>
|
|
<a id='x1-42168r76'></a><span class='ecrm-0500'>76</span><span class='ectt-0800'> </span><span id='textcolor1664'><span class='ectt-0800'>return</span></span><span class='ectt-0800'> i;</span>
|
|
<a id='x1-42170r77'></a><span class='ecrm-0500'>77</span><span class='ectt-0800'>}</span>
|
|
<a id='x1-42172r78'></a><span class='ecrm-0500'>78</span>
|
|
<a id='x1-42174r79'></a><span class='ecrm-0500'>79</span><span id='textcolor1665'><span class='ectt-0800'>/* 1 if the file is currently open by somebody */</span></span>
|
|
<a id='x1-42176r80'></a><span class='ecrm-0500'>80</span><span id='textcolor1666'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> atomic_t already_open = ATOMIC_INIT(0);</span>
|
|
<a id='x1-42178r81'></a><span class='ecrm-0500'>81</span>
|
|
<a id='x1-42180r82'></a><span class='ecrm-0500'>82</span><span id='textcolor1667'><span class='ectt-0800'>/* Queue of processes who want our file */</span></span>
|
|
<a id='x1-42182r83'></a><span class='ecrm-0500'>83</span><span id='textcolor1668'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> DECLARE_WAIT_QUEUE_HEAD(waitq);</span>
|
|
<a id='x1-42184r84'></a><span class='ecrm-0500'>84</span>
|
|
<a id='x1-42186r85'></a><span class='ecrm-0500'>85</span><span id='textcolor1669'><span class='ectt-0800'>/* Called when the /proc file is opened */</span></span>
|
|
<a id='x1-42188r86'></a><span class='ecrm-0500'>86</span><span id='textcolor1670'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor1671'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> module_open(</span><span id='textcolor1672'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> inode *inode, </span><span id='textcolor1673'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> file *file)</span>
|
|
<a id='x1-42190r87'></a><span class='ecrm-0500'>87</span><span class='ectt-0800'>{</span>
|
|
<a id='x1-42192r88'></a><span class='ecrm-0500'>88</span><span class='ectt-0800'> </span><span id='textcolor1674'><span class='ectt-0800'>/* If the file</span><span class='tctt-0800'>'</span><span class='ectt-0800'>s flags include O_NONBLOCK, it means the process does not</span></span>
|
|
<a id='x1-42194r89'></a><span class='ecrm-0500'>89</span><span id='textcolor1675'><span class='ectt-0800'> * want to wait for the file. In this case, if the file is already open,</span></span>
|
|
<a id='x1-42196r90'></a><span class='ecrm-0500'>90</span><span id='textcolor1676'><span class='ectt-0800'> * we should fail with -EAGAIN, meaning "you will have to try again",</span></span>
|
|
<a id='x1-42198r91'></a><span class='ecrm-0500'>91</span><span id='textcolor1677'><span class='ectt-0800'> * instead of blocking a process which would rather stay awake.</span></span>
|
|
<a id='x1-42200r92'></a><span class='ecrm-0500'>92</span><span id='textcolor1678'><span class='ectt-0800'> */</span></span>
|
|
<a id='x1-42202r93'></a><span class='ecrm-0500'>93</span><span class='ectt-0800'> </span><span id='textcolor1679'><span class='ectt-0800'>if</span></span><span class='ectt-0800'> ((file->f_flags & O_NONBLOCK) && atomic_read(&already_open))</span>
|
|
<a id='x1-42204r94'></a><span class='ecrm-0500'>94</span><span class='ectt-0800'> </span><span id='textcolor1680'><span class='ectt-0800'>return</span></span><span class='ectt-0800'> -EAGAIN;</span>
|
|
<a id='x1-42206r95'></a><span class='ecrm-0500'>95</span>
|
|
<a id='x1-42208r96'></a><span class='ecrm-0500'>96</span><span class='ectt-0800'> </span><span id='textcolor1681'><span class='ectt-0800'>/* This is the correct place for try_module_get(THIS_MODULE) because if</span></span>
|
|
<a id='x1-42210r97'></a><span class='ecrm-0500'>97</span><span id='textcolor1682'><span class='ectt-0800'> * a process is in the loop, which is within the kernel module,</span></span>
|
|
<a id='x1-42212r98'></a><span class='ecrm-0500'>98</span><span id='textcolor1683'><span class='ectt-0800'> * the kernel module must not be removed.</span></span>
|
|
<a id='x1-42214r99'></a><span class='ecrm-0500'>99</span><span id='textcolor1684'><span class='ectt-0800'> */</span></span>
|
|
<a id='x1-42216r100'></a><span class='ecrm-0500'>100</span><span class='ectt-0800'> try_module_get(THIS_MODULE);</span>
|
|
<a id='x1-42218r101'></a><span class='ecrm-0500'>101</span>
|
|
<a id='x1-42220r102'></a><span class='ecrm-0500'>102</span><span class='ectt-0800'> </span><span id='textcolor1685'><span class='ectt-0800'>while</span></span><span class='ectt-0800'> (atomic_cmpxchg(&already_open, 0, 1)) {</span>
|
|
<a id='x1-42222r103'></a><span class='ecrm-0500'>103</span><span class='ectt-0800'> </span><span id='textcolor1686'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> i, is_sig = 0;</span>
|
|
<a id='x1-42224r104'></a><span class='ecrm-0500'>104</span>
|
|
<a id='x1-42226r105'></a><span class='ecrm-0500'>105</span><span class='ectt-0800'> </span><span id='textcolor1687'><span class='ectt-0800'>/* This function puts the current process, including any system</span></span>
|
|
<a id='x1-42228r106'></a><span class='ecrm-0500'>106</span><span id='textcolor1688'><span class='ectt-0800'> * calls, such as us, to sleep. Execution will be resumed right</span></span>
|
|
<a id='x1-42230r107'></a><span class='ecrm-0500'>107</span><span id='textcolor1689'><span class='ectt-0800'> * after the function call, either because somebody called</span></span>
|
|
<a id='x1-42232r108'></a><span class='ecrm-0500'>108</span><span id='textcolor1690'><span class='ectt-0800'> * wake_up(&waitq) (only module_close does that, when the file</span></span>
|
|
<a id='x1-42234r109'></a><span class='ecrm-0500'>109</span><span id='textcolor1691'><span class='ectt-0800'> * is closed) or when a signal, such as Ctrl-C, is sent</span></span>
|
|
<a id='x1-42236r110'></a><span class='ecrm-0500'>110</span><span id='textcolor1692'><span class='ectt-0800'> * to the process</span></span>
|
|
<a id='x1-42238r111'></a><span class='ecrm-0500'>111</span><span id='textcolor1693'><span class='ectt-0800'> */</span></span>
|
|
<a id='x1-42240r112'></a><span class='ecrm-0500'>112</span><span class='ectt-0800'> wait_event_interruptible(waitq, !atomic_read(&already_open));</span>
|
|
<a id='x1-42242r113'></a><span class='ecrm-0500'>113</span>
|
|
<a id='x1-42244r114'></a><span class='ecrm-0500'>114</span><span class='ectt-0800'> </span><span id='textcolor1694'><span class='ectt-0800'>/* If we woke up because we got a signal we</span><span class='tctt-0800'>'</span><span class='ectt-0800'>re not blocking,</span></span>
|
|
<a id='x1-42246r115'></a><span class='ecrm-0500'>115</span><span id='textcolor1695'><span class='ectt-0800'> * return -EINTR (fail the system call). This allows processes</span></span>
|
|
<a id='x1-42248r116'></a><span class='ecrm-0500'>116</span><span id='textcolor1696'><span class='ectt-0800'> * to be killed or stopped.</span></span>
|
|
<a id='x1-42250r117'></a><span class='ecrm-0500'>117</span><span id='textcolor1697'><span class='ectt-0800'> */</span></span>
|
|
<a id='x1-42252r118'></a><span class='ecrm-0500'>118</span><span class='ectt-0800'> </span><span id='textcolor1698'><span class='ectt-0800'>for</span></span><span class='ectt-0800'> (i = 0; i < _NSIG_WORDS && !is_sig; i++)</span>
|
|
<a id='x1-42254r119'></a><span class='ecrm-0500'>119</span><span class='ectt-0800'> is_sig = current->pending.signal.sig[i] & ~current->blocked.sig[i];</span>
|
|
<a id='x1-42256r120'></a><span class='ecrm-0500'>120</span>
|
|
<a id='x1-42258r121'></a><span class='ecrm-0500'>121</span><span class='ectt-0800'> </span><span id='textcolor1699'><span class='ectt-0800'>if</span></span><span class='ectt-0800'> (is_sig) {</span>
|
|
<a id='x1-42260r122'></a><span class='ecrm-0500'>122</span><span class='ectt-0800'> </span><span id='textcolor1700'><span class='ectt-0800'>/* It is important to put module_put(THIS_MODULE) here, because</span></span>
|
|
<a id='x1-42262r123'></a><span class='ecrm-0500'>123</span><span id='textcolor1701'><span class='ectt-0800'> * for processes where the open is interrupted there will never</span></span>
|
|
<a id='x1-42264r124'></a><span class='ecrm-0500'>124</span><span id='textcolor1702'><span class='ectt-0800'> * be a corresponding close. If we do not decrement the usage</span></span>
|
|
<a id='x1-42266r125'></a><span class='ecrm-0500'>125</span><span id='textcolor1703'><span class='ectt-0800'> * count here, we will be left with a positive usage count</span></span>
|
|
<a id='x1-42268r126'></a><span class='ecrm-0500'>126</span><span id='textcolor1704'><span class='ectt-0800'> * which we will have no way to bring down to zero, giving us</span></span>
|
|
<a id='x1-42270r127'></a><span class='ecrm-0500'>127</span><span id='textcolor1705'><span class='ectt-0800'> * an immortal module, which can only be killed by rebooting</span></span>
|
|
<a id='x1-42272r128'></a><span class='ecrm-0500'>128</span><span id='textcolor1706'><span class='ectt-0800'> * the machine.</span></span>
|
|
<a id='x1-42274r129'></a><span class='ecrm-0500'>129</span><span id='textcolor1707'><span class='ectt-0800'> */</span></span>
|
|
<a id='x1-42276r130'></a><span class='ecrm-0500'>130</span><span class='ectt-0800'> module_put(THIS_MODULE);</span>
|
|
<a id='x1-42278r131'></a><span class='ecrm-0500'>131</span><span class='ectt-0800'> </span><span id='textcolor1708'><span class='ectt-0800'>return</span></span><span class='ectt-0800'> -EINTR;</span>
|
|
<a id='x1-42280r132'></a><span class='ecrm-0500'>132</span><span class='ectt-0800'> }</span>
|
|
<a id='x1-42282r133'></a><span class='ecrm-0500'>133</span><span class='ectt-0800'> }</span>
|
|
<a id='x1-42284r134'></a><span class='ecrm-0500'>134</span>
|
|
<a id='x1-42286r135'></a><span class='ecrm-0500'>135</span><span class='ectt-0800'> </span><span id='textcolor1709'><span class='ectt-0800'>return</span></span><span class='ectt-0800'> 0; </span><span id='textcolor1710'><span class='ectt-0800'>/* Allow the access */</span></span>
|
|
<a id='x1-42288r136'></a><span class='ecrm-0500'>136</span><span class='ectt-0800'>}</span>
|
|
<a id='x1-42290r137'></a><span class='ecrm-0500'>137</span>
|
|
<a id='x1-42292r138'></a><span class='ecrm-0500'>138</span><span id='textcolor1711'><span class='ectt-0800'>/* Called when the /proc file is closed */</span></span>
|
|
<a id='x1-42294r139'></a><span class='ecrm-0500'>139</span><span id='textcolor1712'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor1713'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> module_close(</span><span id='textcolor1714'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> inode *inode, </span><span id='textcolor1715'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> file *file)</span>
|
|
<a id='x1-42296r140'></a><span class='ecrm-0500'>140</span><span class='ectt-0800'>{</span>
|
|
<a id='x1-42298r141'></a><span class='ecrm-0500'>141</span><span class='ectt-0800'> </span><span id='textcolor1716'><span class='ectt-0800'>/* Set already_open to zero, so one of the processes in the waitq will</span></span>
|
|
<a id='x1-42300r142'></a><span class='ecrm-0500'>142</span><span id='textcolor1717'><span class='ectt-0800'> * be able to set already_open back to one and to open the file. All</span></span>
|
|
<a id='x1-42302r143'></a><span class='ecrm-0500'>143</span><span id='textcolor1718'><span class='ectt-0800'> * the other processes will be called when already_open is back to one,</span></span>
|
|
<a id='x1-42304r144'></a><span class='ecrm-0500'>144</span><span id='textcolor1719'><span class='ectt-0800'> * so they</span><span class='tctt-0800'>'</span><span class='ectt-0800'>ll go back to sleep.</span></span>
|
|
<a id='x1-42306r145'></a><span class='ecrm-0500'>145</span><span id='textcolor1720'><span class='ectt-0800'> */</span></span>
|
|
<a id='x1-42308r146'></a><span class='ecrm-0500'>146</span><span class='ectt-0800'> atomic_set(&already_open, 0);</span>
|
|
<a id='x1-42310r147'></a><span class='ecrm-0500'>147</span>
|
|
<a id='x1-42312r148'></a><span class='ecrm-0500'>148</span><span class='ectt-0800'> </span><span id='textcolor1721'><span class='ectt-0800'>/* Wake up all the processes in waitq, so if anybody is waiting for the</span></span>
|
|
<a id='x1-42314r149'></a><span class='ecrm-0500'>149</span><span id='textcolor1722'><span class='ectt-0800'> * file, they can have it.</span></span>
|
|
<a id='x1-42316r150'></a><span class='ecrm-0500'>150</span><span id='textcolor1723'><span class='ectt-0800'> */</span></span>
|
|
<a id='x1-42318r151'></a><span class='ecrm-0500'>151</span><span class='ectt-0800'> wake_up(&waitq);</span>
|
|
<a id='x1-42320r152'></a><span class='ecrm-0500'>152</span>
|
|
<a id='x1-42322r153'></a><span class='ecrm-0500'>153</span><span class='ectt-0800'> module_put(THIS_MODULE);</span>
|
|
<a id='x1-42324r154'></a><span class='ecrm-0500'>154</span>
|
|
<a id='x1-42326r155'></a><span class='ecrm-0500'>155</span><span class='ectt-0800'> </span><span id='textcolor1724'><span class='ectt-0800'>return</span></span><span class='ectt-0800'> 0; </span><span id='textcolor1725'><span class='ectt-0800'>/* success */</span></span>
|
|
<a id='x1-42328r156'></a><span class='ecrm-0500'>156</span><span class='ectt-0800'>}</span>
|
|
<a id='x1-42330r157'></a><span class='ecrm-0500'>157</span>
|
|
<a id='x1-42332r158'></a><span class='ecrm-0500'>158</span><span id='textcolor1726'><span class='ectt-0800'>/* Structures to register as the /proc file, with pointers to all the relevant</span></span>
|
|
<a id='x1-42334r159'></a><span class='ecrm-0500'>159</span><span id='textcolor1727'><span class='ectt-0800'> * functions.</span></span>
|
|
<a id='x1-42336r160'></a><span class='ecrm-0500'>160</span><span id='textcolor1728'><span class='ectt-0800'> */</span></span>
|
|
<a id='x1-42338r161'></a><span class='ecrm-0500'>161</span>
|
|
<a id='x1-42340r162'></a><span class='ecrm-0500'>162</span><span id='textcolor1729'><span class='ectt-0800'>/* File operations for our proc file. This is where we place pointers to all</span></span>
|
|
<a id='x1-42342r163'></a><span class='ecrm-0500'>163</span><span id='textcolor1730'><span class='ectt-0800'> * the functions called when somebody tries to do something to our file. NULL</span></span>
|
|
<a id='x1-42344r164'></a><span class='ecrm-0500'>164</span><span id='textcolor1731'><span class='ectt-0800'> * means we don</span><span class='tctt-0800'>'</span><span class='ectt-0800'>t want to deal with something.</span></span>
|
|
<a id='x1-42346r165'></a><span class='ecrm-0500'>165</span><span id='textcolor1732'><span class='ectt-0800'> */</span></span>
|
|
<a id='x1-42348r166'></a><span class='ecrm-0500'>166</span><span id='textcolor1733'><span class='ectt-0800'>#ifdef HAVE_PROC_OPS</span></span>
|
|
<a id='x1-42350r167'></a><span class='ecrm-0500'>167</span><span id='textcolor1734'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor1735'><span class='ectt-0800'>const</span></span><span class='ectt-0800'> </span><span id='textcolor1736'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> proc_ops file_ops_4_our_proc_file = {</span>
|
|
<a id='x1-42352r168'></a><span class='ecrm-0500'>168</span><span class='ectt-0800'> .proc_read = module_output, </span><span id='textcolor1737'><span class='ectt-0800'>/* "read" from the file */</span></span>
|
|
<a id='x1-42354r169'></a><span class='ecrm-0500'>169</span><span class='ectt-0800'> .proc_write = module_input, </span><span id='textcolor1738'><span class='ectt-0800'>/* "write" to the file */</span></span>
|
|
<a id='x1-42356r170'></a><span class='ecrm-0500'>170</span><span class='ectt-0800'> .proc_open = module_open, </span><span id='textcolor1739'><span class='ectt-0800'>/* called when the /proc file is opened */</span></span>
|
|
<a id='x1-42358r171'></a><span class='ecrm-0500'>171</span><span class='ectt-0800'> .proc_release = module_close, </span><span id='textcolor1740'><span class='ectt-0800'>/* called when it</span><span class='tctt-0800'>'</span><span class='ectt-0800'>s closed */</span></span>
|
|
<a id='x1-42360r172'></a><span class='ecrm-0500'>172</span><span class='ectt-0800'>};</span>
|
|
<a id='x1-42362r173'></a><span class='ecrm-0500'>173</span><span id='textcolor1741'><span class='ectt-0800'>#else</span></span>
|
|
<a id='x1-42364r174'></a><span class='ecrm-0500'>174</span><span id='textcolor1742'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor1743'><span class='ectt-0800'>const</span></span><span class='ectt-0800'> </span><span id='textcolor1744'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> file_operations file_ops_4_our_proc_file = {</span>
|
|
<a id='x1-42366r175'></a><span class='ecrm-0500'>175</span><span class='ectt-0800'> .read = module_output,</span>
|
|
<a id='x1-42368r176'></a><span class='ecrm-0500'>176</span><span class='ectt-0800'> .write = module_input,</span>
|
|
<a id='x1-42370r177'></a><span class='ecrm-0500'>177</span><span class='ectt-0800'> .open = module_open,</span>
|
|
<a id='x1-42372r178'></a><span class='ecrm-0500'>178</span><span class='ectt-0800'> .release = module_close,</span>
|
|
<a id='x1-42374r179'></a><span class='ecrm-0500'>179</span><span class='ectt-0800'>};</span>
|
|
<a id='x1-42376r180'></a><span class='ecrm-0500'>180</span><span id='textcolor1745'><span class='ectt-0800'>#endif</span></span>
|
|
<a id='x1-42378r181'></a><span class='ecrm-0500'>181</span>
|
|
<a id='x1-42380r182'></a><span class='ecrm-0500'>182</span><span id='textcolor1746'><span class='ectt-0800'>/* Initialize the module - register the proc file */</span></span>
|
|
<a id='x1-42382r183'></a><span class='ecrm-0500'>183</span><span id='textcolor1747'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor1748'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> __init sleep_init(</span><span id='textcolor1749'><span class='ectt-0800'>void</span></span><span class='ectt-0800'>)</span>
|
|
<a id='x1-42384r184'></a><span class='ecrm-0500'>184</span><span class='ectt-0800'>{</span>
|
|
<a id='x1-42386r185'></a><span class='ecrm-0500'>185</span><span class='ectt-0800'> our_proc_file =</span>
|
|
<a id='x1-42388r186'></a><span class='ecrm-0500'>186</span><span class='ectt-0800'> proc_create(PROC_ENTRY_FILENAME, 0644, NULL, &file_ops_4_our_proc_file);</span>
|
|
<a id='x1-42390r187'></a><span class='ecrm-0500'>187</span><span class='ectt-0800'> </span><span id='textcolor1750'><span class='ectt-0800'>if</span></span><span class='ectt-0800'> (our_proc_file == NULL) {</span>
|
|
<a id='x1-42392r188'></a><span class='ecrm-0500'>188</span><span class='ectt-0800'> remove_proc_entry(PROC_ENTRY_FILENAME, NULL);</span>
|
|
<a id='x1-42394r189'></a><span class='ecrm-0500'>189</span><span class='ectt-0800'> pr_debug(</span><span id='textcolor1751'><span class='ectt-0800'>"Error: Could not initialize /proc/%s</span></span><span id='textcolor1752'><span class='ectt-0800'>\n</span></span><span id='textcolor1753'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>, PROC_ENTRY_FILENAME);</span>
|
|
<a id='x1-42396r190'></a><span class='ecrm-0500'>190</span><span class='ectt-0800'> </span><span id='textcolor1754'><span class='ectt-0800'>return</span></span><span class='ectt-0800'> -ENOMEM;</span>
|
|
<a id='x1-42398r191'></a><span class='ecrm-0500'>191</span><span class='ectt-0800'> }</span>
|
|
<a id='x1-42400r192'></a><span class='ecrm-0500'>192</span><span class='ectt-0800'> proc_set_size(our_proc_file, 80);</span>
|
|
<a id='x1-42402r193'></a><span class='ecrm-0500'>193</span><span class='ectt-0800'> proc_set_user(our_proc_file, GLOBAL_ROOT_UID, GLOBAL_ROOT_GID);</span>
|
|
<a id='x1-42404r194'></a><span class='ecrm-0500'>194</span>
|
|
<a id='x1-42406r195'></a><span class='ecrm-0500'>195</span><span class='ectt-0800'> pr_info(</span><span id='textcolor1755'><span class='ectt-0800'>"/proc/%s created</span></span><span id='textcolor1756'><span class='ectt-0800'>\n</span></span><span id='textcolor1757'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>, PROC_ENTRY_FILENAME);</span>
|
|
<a id='x1-42408r196'></a><span class='ecrm-0500'>196</span>
|
|
<a id='x1-42410r197'></a><span class='ecrm-0500'>197</span><span class='ectt-0800'> </span><span id='textcolor1758'><span class='ectt-0800'>return</span></span><span class='ectt-0800'> 0;</span>
|
|
<a id='x1-42412r198'></a><span class='ecrm-0500'>198</span><span class='ectt-0800'>}</span>
|
|
<a id='x1-42414r199'></a><span class='ecrm-0500'>199</span>
|
|
<a id='x1-42416r200'></a><span class='ecrm-0500'>200</span><span id='textcolor1759'><span class='ectt-0800'>/* Cleanup - unregister our file from /proc. This could get dangerous if</span></span>
|
|
<a id='x1-42418r201'></a><span class='ecrm-0500'>201</span><span id='textcolor1760'><span class='ectt-0800'> * there are still processes waiting in waitq, because they are inside our</span></span>
|
|
<a id='x1-42420r202'></a><span class='ecrm-0500'>202</span><span id='textcolor1761'><span class='ectt-0800'> * open function, which will get unloaded. I</span><span class='tctt-0800'>'</span><span class='ectt-0800'>ll explain how to avoid removal</span></span>
|
|
<a id='x1-42422r203'></a><span class='ecrm-0500'>203</span><span id='textcolor1762'><span class='ectt-0800'> * of a kernel module in such a case in chapter 10.</span></span>
|
|
<a id='x1-42424r204'></a><span class='ecrm-0500'>204</span><span id='textcolor1763'><span class='ectt-0800'> */</span></span>
|
|
<a id='x1-42426r205'></a><span class='ecrm-0500'>205</span><span id='textcolor1764'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor1765'><span class='ectt-0800'>void</span></span><span class='ectt-0800'> __exit sleep_exit(</span><span id='textcolor1766'><span class='ectt-0800'>void</span></span><span class='ectt-0800'>)</span>
|
|
<a id='x1-42428r206'></a><span class='ecrm-0500'>206</span><span class='ectt-0800'>{</span>
|
|
<a id='x1-42430r207'></a><span class='ecrm-0500'>207</span><span class='ectt-0800'> remove_proc_entry(PROC_ENTRY_FILENAME, NULL);</span>
|
|
<a id='x1-42432r208'></a><span class='ecrm-0500'>208</span><span class='ectt-0800'> pr_debug(</span><span id='textcolor1767'><span class='ectt-0800'>"/proc/%s removed</span></span><span id='textcolor1768'><span class='ectt-0800'>\n</span></span><span id='textcolor1769'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>, PROC_ENTRY_FILENAME);</span>
|
|
<a id='x1-42434r209'></a><span class='ecrm-0500'>209</span><span class='ectt-0800'>}</span>
|
|
<a id='x1-42436r210'></a><span class='ecrm-0500'>210</span>
|
|
<a id='x1-42438r211'></a><span class='ecrm-0500'>211</span><span class='ectt-0800'>module_init(sleep_init);</span>
|
|
<a id='x1-42440r212'></a><span class='ecrm-0500'>212</span><span class='ectt-0800'>module_exit(sleep_exit);</span>
|
|
<a id='x1-42442r213'></a><span class='ecrm-0500'>213</span>
|
|
<a id='x1-42444r214'></a><span class='ecrm-0500'>214</span><span class='ectt-0800'>MODULE_LICENSE(</span><span id='textcolor1770'><span class='ectt-0800'>"GPL"</span></span><span class='ectt-0800'>);</span></pre>
|
|
|
|
<!-- l. 1 --><p class='indent'>
|
|
</p>
|
|
<pre class='fancyvrb' id='fancyvrb55'><a id='x1-42446r1'></a><span class='ecrm-0500'>1</span><span id='textcolor1771'><span class='ectt-0800'>/*</span></span>
|
|
<a id='x1-42448r2'></a><span class='ecrm-0500'>2</span><span id='textcolor1772'><span class='ectt-0800'> * cat_nonblock.c - open a file and display its contents, but exit rather than</span></span>
|
|
<a id='x1-42450r3'></a><span class='ecrm-0500'>3</span><span id='textcolor1773'><span class='ectt-0800'> * wait for input.</span></span>
|
|
<a id='x1-42452r4'></a><span class='ecrm-0500'>4</span><span id='textcolor1774'><span class='ectt-0800'> */</span></span>
|
|
<a id='x1-42454r5'></a><span class='ecrm-0500'>5</span><span id='textcolor1775'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor1776'><span class='ectt-0800'><errno.h> /* for errno */</span></span>
|
|
<a id='x1-42456r6'></a><span class='ecrm-0500'>6</span><span id='textcolor1777'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor1778'><span class='ectt-0800'><fcntl.h> /* for open */</span></span>
|
|
<a id='x1-42458r7'></a><span class='ecrm-0500'>7</span><span id='textcolor1779'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor1780'><span class='ectt-0800'><stdio.h> /* standard I/O */</span></span>
|
|
<a id='x1-42460r8'></a><span class='ecrm-0500'>8</span><span id='textcolor1781'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor1782'><span class='ectt-0800'><stdlib.h> /* for exit */</span></span>
|
|
<a id='x1-42462r9'></a><span class='ecrm-0500'>9</span><span id='textcolor1783'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor1784'><span class='ectt-0800'><unistd.h> /* for read */</span></span>
|
|
<a id='x1-42464r10'></a><span class='ecrm-0500'>10</span>
|
|
<a id='x1-42466r11'></a><span class='ecrm-0500'>11</span><span id='textcolor1785'><span class='ectt-0800'>#define MAX_BYTES 1024 * 4</span></span>
|
|
<a id='x1-42468r12'></a><span class='ecrm-0500'>12</span>
|
|
<a id='x1-42470r13'></a><span class='ecrm-0500'>13</span><span id='textcolor1786'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> main(</span><span id='textcolor1787'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> argc, </span><span id='textcolor1788'><span class='ectt-0800'>char</span></span><span class='ectt-0800'> *argv[])</span>
|
|
<a id='x1-42472r14'></a><span class='ecrm-0500'>14</span><span class='ectt-0800'>{</span>
|
|
<a id='x1-42474r15'></a><span class='ecrm-0500'>15</span><span class='ectt-0800'> </span><span id='textcolor1789'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> fd; </span><span id='textcolor1790'><span class='ectt-0800'>/* The file descriptor for the file to read */</span></span>
|
|
<a id='x1-42476r16'></a><span class='ecrm-0500'>16</span><span class='ectt-0800'> </span><span id='textcolor1791'><span class='ectt-0800'>size_t</span></span><span class='ectt-0800'> bytes; </span><span id='textcolor1792'><span class='ectt-0800'>/* The number of bytes read */</span></span>
|
|
<a id='x1-42478r17'></a><span class='ecrm-0500'>17</span><span class='ectt-0800'> </span><span id='textcolor1793'><span class='ectt-0800'>char</span></span><span class='ectt-0800'> buffer[MAX_BYTES]; </span><span id='textcolor1794'><span class='ectt-0800'>/* The buffer for the bytes */</span></span>
|
|
<a id='x1-42480r18'></a><span class='ecrm-0500'>18</span>
|
|
<a id='x1-42482r19'></a><span class='ecrm-0500'>19</span><span class='ectt-0800'> </span><span id='textcolor1795'><span class='ectt-0800'>/* Usage */</span></span>
|
|
<a id='x1-42484r20'></a><span class='ecrm-0500'>20</span><span class='ectt-0800'> </span><span id='textcolor1796'><span class='ectt-0800'>if</span></span><span class='ectt-0800'> (argc != 2) {</span>
|
|
<a id='x1-42486r21'></a><span class='ecrm-0500'>21</span><span class='ectt-0800'> printf(</span><span id='textcolor1797'><span class='ectt-0800'>"Usage: %s <filename></span></span><span id='textcolor1798'><span class='ectt-0800'>\n</span></span><span id='textcolor1799'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>, argv[0]);</span>
|
|
<a id='x1-42488r22'></a><span class='ecrm-0500'>22</span><span class='ectt-0800'> puts(</span><span id='textcolor1800'><span class='ectt-0800'>"Reads the content of a file, but doesn</span><span class='tctt-0800'>'</span><span class='ectt-0800'>t wait for input"</span></span><span class='ectt-0800'>);</span>
|
|
<a id='x1-42490r23'></a><span class='ecrm-0500'>23</span><span class='ectt-0800'> exit(-1);</span>
|
|
<a id='x1-42492r24'></a><span class='ecrm-0500'>24</span><span class='ectt-0800'> }</span>
|
|
<a id='x1-42494r25'></a><span class='ecrm-0500'>25</span>
|
|
<a id='x1-42496r26'></a><span class='ecrm-0500'>26</span><span class='ectt-0800'> </span><span id='textcolor1801'><span class='ectt-0800'>/* Open the file for reading in non blocking mode */</span></span>
|
|
<a id='x1-42498r27'></a><span class='ecrm-0500'>27</span><span class='ectt-0800'> fd = open(argv[1], O_RDONLY | O_NONBLOCK);</span>
|
|
<a id='x1-42500r28'></a><span class='ecrm-0500'>28</span>
|
|
<a id='x1-42502r29'></a><span class='ecrm-0500'>29</span><span class='ectt-0800'> </span><span id='textcolor1802'><span class='ectt-0800'>/* If open failed */</span></span>
|
|
<a id='x1-42504r30'></a><span class='ecrm-0500'>30</span><span class='ectt-0800'> </span><span id='textcolor1803'><span class='ectt-0800'>if</span></span><span class='ectt-0800'> (fd == -1) {</span>
|
|
<a id='x1-42506r31'></a><span class='ecrm-0500'>31</span><span class='ectt-0800'> puts(errno == EAGAIN ? </span><span id='textcolor1804'><span class='ectt-0800'>"Open would block"</span></span><span class='ectt-0800'> : </span><span id='textcolor1805'><span class='ectt-0800'>"Open failed"</span></span><span class='ectt-0800'>);</span>
|
|
<a id='x1-42508r32'></a><span class='ecrm-0500'>32</span><span class='ectt-0800'> exit(-1);</span>
|
|
<a id='x1-42510r33'></a><span class='ecrm-0500'>33</span><span class='ectt-0800'> }</span>
|
|
<a id='x1-42512r34'></a><span class='ecrm-0500'>34</span>
|
|
<a id='x1-42514r35'></a><span class='ecrm-0500'>35</span><span class='ectt-0800'> </span><span id='textcolor1806'><span class='ectt-0800'>/* Read the file and output its contents */</span></span>
|
|
<a id='x1-42516r36'></a><span class='ecrm-0500'>36</span><span class='ectt-0800'> </span><span id='textcolor1807'><span class='ectt-0800'>do</span></span><span class='ectt-0800'> {</span>
|
|
<a id='x1-42518r37'></a><span class='ecrm-0500'>37</span><span class='ectt-0800'> </span><span id='textcolor1808'><span class='ectt-0800'>/* Read characters from the file */</span></span>
|
|
<a id='x1-42520r38'></a><span class='ecrm-0500'>38</span><span class='ectt-0800'> bytes = read(fd, buffer, MAX_BYTES);</span>
|
|
<a id='x1-42522r39'></a><span class='ecrm-0500'>39</span>
|
|
<a id='x1-42524r40'></a><span class='ecrm-0500'>40</span><span class='ectt-0800'> </span><span id='textcolor1809'><span class='ectt-0800'>/* If there</span><span class='tctt-0800'>'</span><span class='ectt-0800'>s an error, report it and die */</span></span>
|
|
<a id='x1-42526r41'></a><span class='ecrm-0500'>41</span><span class='ectt-0800'> </span><span id='textcolor1810'><span class='ectt-0800'>if</span></span><span class='ectt-0800'> (bytes == -1) {</span>
|
|
<a id='x1-42528r42'></a><span class='ecrm-0500'>42</span><span class='ectt-0800'> </span><span id='textcolor1811'><span class='ectt-0800'>if</span></span><span class='ectt-0800'> (errno == EAGAIN)</span>
|
|
<a id='x1-42530r43'></a><span class='ecrm-0500'>43</span><span class='ectt-0800'> puts(</span><span id='textcolor1812'><span class='ectt-0800'>"Normally I</span><span class='tctt-0800'>'</span><span class='ectt-0800'>d block, but you told me not to"</span></span><span class='ectt-0800'>);</span>
|
|
<a id='x1-42532r44'></a><span class='ecrm-0500'>44</span><span class='ectt-0800'> </span><span id='textcolor1813'><span class='ectt-0800'>else</span></span>
|
|
<a id='x1-42534r45'></a><span class='ecrm-0500'>45</span><span class='ectt-0800'> puts(</span><span id='textcolor1814'><span class='ectt-0800'>"Another read error"</span></span><span class='ectt-0800'>);</span>
|
|
<a id='x1-42536r46'></a><span class='ecrm-0500'>46</span><span class='ectt-0800'> exit(-1);</span>
|
|
<a id='x1-42538r47'></a><span class='ecrm-0500'>47</span><span class='ectt-0800'> }</span>
|
|
<a id='x1-42540r48'></a><span class='ecrm-0500'>48</span>
|
|
<a id='x1-42542r49'></a><span class='ecrm-0500'>49</span><span class='ectt-0800'> </span><span id='textcolor1815'><span class='ectt-0800'>/* Print the characters */</span></span>
|
|
<a id='x1-42544r50'></a><span class='ecrm-0500'>50</span><span class='ectt-0800'> </span><span id='textcolor1816'><span class='ectt-0800'>if</span></span><span class='ectt-0800'> (bytes > 0) {</span>
|
|
<a id='x1-42546r51'></a><span class='ecrm-0500'>51</span><span class='ectt-0800'> </span><span id='textcolor1817'><span class='ectt-0800'>for</span></span><span class='ectt-0800'> (</span><span id='textcolor1818'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> i = 0; i < bytes; i++)</span>
|
|
<a id='x1-42548r52'></a><span class='ecrm-0500'>52</span><span class='ectt-0800'> putchar(buffer[i]);</span>
|
|
<a id='x1-42550r53'></a><span class='ecrm-0500'>53</span><span class='ectt-0800'> }</span>
|
|
<a id='x1-42552r54'></a><span class='ecrm-0500'>54</span>
|
|
<a id='x1-42554r55'></a><span class='ecrm-0500'>55</span><span class='ectt-0800'> </span><span id='textcolor1819'><span class='ectt-0800'>/* While there are no errors and the file isn</span><span class='tctt-0800'>'</span><span class='ectt-0800'>t over */</span></span>
|
|
<a id='x1-42556r56'></a><span class='ecrm-0500'>56</span><span class='ectt-0800'> } </span><span id='textcolor1820'><span class='ectt-0800'>while</span></span><span class='ectt-0800'> (bytes > 0);</span>
|
|
<a id='x1-42558r57'></a><span class='ecrm-0500'>57</span>
|
|
<a id='x1-42560r58'></a><span class='ecrm-0500'>58</span><span class='ectt-0800'> </span><span id='textcolor1821'><span class='ectt-0800'>return</span></span><span class='ectt-0800'> 0;</span>
|
|
<a id='x1-42562r59'></a><span class='ecrm-0500'>59</span><span class='ectt-0800'>}</span></pre>
|
|
<!-- l. 1418 --><p class='noindent'>
|
|
</p>
|
|
<h4 class='subsectionHead' id='completions'><span class='titlemark'>11.2 </span> <a id='x1-4300011.2'></a>Completions</h4>
|
|
<!-- l. 1420 --><p class='noindent'>Sometimes one thing should happen before another within a module having multiple threads.
|
|
Rather than using <code> <span class='ectt-1000'>/bin/sleep</span>
|
|
</code> commands, the kernel has another way to do this which allows timeouts or
|
|
interrupts to also happen.
|
|
</p><!-- l. 1423 --><p class='indent'> In the following example two threads are started, but one needs to start before
|
|
another.
|
|
</p><!-- l. 1 --><p class='indent'>
|
|
|
|
|
|
|
|
</p>
|
|
<pre class='fancyvrb' id='fancyvrb56'><a id='x1-43003r1'></a><span class='ecrm-0500'>1</span><span id='textcolor1822'><span class='ectt-0800'>/*</span></span>
|
|
<a id='x1-43005r2'></a><span class='ecrm-0500'>2</span><span id='textcolor1823'><span class='ectt-0800'> * completions.c</span></span>
|
|
<a id='x1-43007r3'></a><span class='ecrm-0500'>3</span><span id='textcolor1824'><span class='ectt-0800'> */</span></span>
|
|
<a id='x1-43009r4'></a><span class='ecrm-0500'>4</span><span id='textcolor1825'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor1826'><span class='ectt-0800'><linux/completion.h></span></span>
|
|
<a id='x1-43011r5'></a><span class='ecrm-0500'>5</span><span id='textcolor1827'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor1828'><span class='ectt-0800'><linux/init.h></span></span>
|
|
<a id='x1-43013r6'></a><span class='ecrm-0500'>6</span><span id='textcolor1829'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor1830'><span class='ectt-0800'><linux/kernel.h></span></span>
|
|
<a id='x1-43015r7'></a><span class='ecrm-0500'>7</span><span id='textcolor1831'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor1832'><span class='ectt-0800'><linux/kthread.h></span></span>
|
|
<a id='x1-43017r8'></a><span class='ecrm-0500'>8</span><span id='textcolor1833'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor1834'><span class='ectt-0800'><linux/module.h></span></span>
|
|
<a id='x1-43019r9'></a><span class='ecrm-0500'>9</span>
|
|
<a id='x1-43021r10'></a><span class='ecrm-0500'>10</span><span id='textcolor1835'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor1836'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> {</span>
|
|
<a id='x1-43023r11'></a><span class='ecrm-0500'>11</span><span class='ectt-0800'> </span><span id='textcolor1837'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> completion crank_comp;</span>
|
|
<a id='x1-43025r12'></a><span class='ecrm-0500'>12</span><span class='ectt-0800'> </span><span id='textcolor1838'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> completion flywheel_comp;</span>
|
|
<a id='x1-43027r13'></a><span class='ecrm-0500'>13</span><span class='ectt-0800'>} machine;</span>
|
|
<a id='x1-43029r14'></a><span class='ecrm-0500'>14</span>
|
|
<a id='x1-43031r15'></a><span class='ecrm-0500'>15</span><span id='textcolor1839'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor1840'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> machine_crank_thread(</span><span id='textcolor1841'><span class='ectt-0800'>void</span></span><span class='ectt-0800'> *arg)</span>
|
|
<a id='x1-43033r16'></a><span class='ecrm-0500'>16</span><span class='ectt-0800'>{</span>
|
|
<a id='x1-43035r17'></a><span class='ecrm-0500'>17</span><span class='ectt-0800'> pr_info(</span><span id='textcolor1842'><span class='ectt-0800'>"Turn the crank</span></span><span id='textcolor1843'><span class='ectt-0800'>\n</span></span><span id='textcolor1844'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>);</span>
|
|
<a id='x1-43037r18'></a><span class='ecrm-0500'>18</span>
|
|
<a id='x1-43039r19'></a><span class='ecrm-0500'>19</span><span class='ectt-0800'> complete_all(&machine.crank_comp);</span>
|
|
<a id='x1-43041r20'></a><span class='ecrm-0500'>20</span><span class='ectt-0800'> complete_and_exit(&machine.crank_comp, 0);</span>
|
|
<a id='x1-43043r21'></a><span class='ecrm-0500'>21</span><span class='ectt-0800'>}</span>
|
|
<a id='x1-43045r22'></a><span class='ecrm-0500'>22</span>
|
|
<a id='x1-43047r23'></a><span class='ecrm-0500'>23</span><span id='textcolor1845'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor1846'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> machine_flywheel_spinup_thread(</span><span id='textcolor1847'><span class='ectt-0800'>void</span></span><span class='ectt-0800'> *arg)</span>
|
|
<a id='x1-43049r24'></a><span class='ecrm-0500'>24</span><span class='ectt-0800'>{</span>
|
|
<a id='x1-43051r25'></a><span class='ecrm-0500'>25</span><span class='ectt-0800'> wait_for_completion(&machine.crank_comp);</span>
|
|
<a id='x1-43053r26'></a><span class='ecrm-0500'>26</span>
|
|
<a id='x1-43055r27'></a><span class='ecrm-0500'>27</span><span class='ectt-0800'> pr_info(</span><span id='textcolor1848'><span class='ectt-0800'>"Flywheel spins up</span></span><span id='textcolor1849'><span class='ectt-0800'>\n</span></span><span id='textcolor1850'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>);</span>
|
|
<a id='x1-43057r28'></a><span class='ecrm-0500'>28</span>
|
|
<a id='x1-43059r29'></a><span class='ecrm-0500'>29</span><span class='ectt-0800'> complete_all(&machine.flywheel_comp);</span>
|
|
<a id='x1-43061r30'></a><span class='ecrm-0500'>30</span><span class='ectt-0800'> complete_and_exit(&machine.flywheel_comp, 0);</span>
|
|
<a id='x1-43063r31'></a><span class='ecrm-0500'>31</span><span class='ectt-0800'>}</span>
|
|
<a id='x1-43065r32'></a><span class='ecrm-0500'>32</span>
|
|
<a id='x1-43067r33'></a><span class='ecrm-0500'>33</span><span id='textcolor1851'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor1852'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> completions_init(</span><span id='textcolor1853'><span class='ectt-0800'>void</span></span><span class='ectt-0800'>)</span>
|
|
<a id='x1-43069r34'></a><span class='ecrm-0500'>34</span><span class='ectt-0800'>{</span>
|
|
<a id='x1-43071r35'></a><span class='ecrm-0500'>35</span><span class='ectt-0800'> </span><span id='textcolor1854'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> task_struct *crank_thread;</span>
|
|
<a id='x1-43073r36'></a><span class='ecrm-0500'>36</span><span class='ectt-0800'> </span><span id='textcolor1855'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> task_struct *flywheel_thread;</span>
|
|
<a id='x1-43075r37'></a><span class='ecrm-0500'>37</span>
|
|
<a id='x1-43077r38'></a><span class='ecrm-0500'>38</span><span class='ectt-0800'> pr_info(</span><span id='textcolor1856'><span class='ectt-0800'>"completions example</span></span><span id='textcolor1857'><span class='ectt-0800'>\n</span></span><span id='textcolor1858'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>);</span>
|
|
<a id='x1-43079r39'></a><span class='ecrm-0500'>39</span>
|
|
<a id='x1-43081r40'></a><span class='ecrm-0500'>40</span><span class='ectt-0800'> init_completion(&machine.crank_comp);</span>
|
|
<a id='x1-43083r41'></a><span class='ecrm-0500'>41</span><span class='ectt-0800'> init_completion(&machine.flywheel_comp);</span>
|
|
<a id='x1-43085r42'></a><span class='ecrm-0500'>42</span>
|
|
<a id='x1-43087r43'></a><span class='ecrm-0500'>43</span><span class='ectt-0800'> crank_thread = kthread_create(machine_crank_thread, NULL, </span><span id='textcolor1859'><span class='ectt-0800'>"KThread Crank"</span></span><span class='ectt-0800'>);</span>
|
|
<a id='x1-43089r44'></a><span class='ecrm-0500'>44</span><span class='ectt-0800'> </span><span id='textcolor1860'><span class='ectt-0800'>if</span></span><span class='ectt-0800'> (IS_ERR(crank_thread))</span>
|
|
<a id='x1-43091r45'></a><span class='ecrm-0500'>45</span><span class='ectt-0800'> </span><span id='textcolor1861'><span class='ectt-0800'>goto</span></span><span class='ectt-0800'> ERROR_THREAD_1;</span>
|
|
<a id='x1-43093r46'></a><span class='ecrm-0500'>46</span>
|
|
<a id='x1-43095r47'></a><span class='ecrm-0500'>47</span><span class='ectt-0800'> flywheel_thread = kthread_create(machine_flywheel_spinup_thread, NULL,</span>
|
|
<a id='x1-43097r48'></a><span class='ecrm-0500'>48</span><span class='ectt-0800'> </span><span id='textcolor1862'><span class='ectt-0800'>"KThread Flywheel"</span></span><span class='ectt-0800'>);</span>
|
|
<a id='x1-43099r49'></a><span class='ecrm-0500'>49</span><span class='ectt-0800'> </span><span id='textcolor1863'><span class='ectt-0800'>if</span></span><span class='ectt-0800'> (IS_ERR(flywheel_thread))</span>
|
|
<a id='x1-43101r50'></a><span class='ecrm-0500'>50</span><span class='ectt-0800'> </span><span id='textcolor1864'><span class='ectt-0800'>goto</span></span><span class='ectt-0800'> ERROR_THREAD_2;</span>
|
|
<a id='x1-43103r51'></a><span class='ecrm-0500'>51</span>
|
|
<a id='x1-43105r52'></a><span class='ecrm-0500'>52</span><span class='ectt-0800'> wake_up_process(flywheel_thread);</span>
|
|
<a id='x1-43107r53'></a><span class='ecrm-0500'>53</span><span class='ectt-0800'> wake_up_process(crank_thread);</span>
|
|
<a id='x1-43109r54'></a><span class='ecrm-0500'>54</span>
|
|
<a id='x1-43111r55'></a><span class='ecrm-0500'>55</span><span class='ectt-0800'> </span><span id='textcolor1865'><span class='ectt-0800'>return</span></span><span class='ectt-0800'> 0;</span>
|
|
<a id='x1-43113r56'></a><span class='ecrm-0500'>56</span>
|
|
<a id='x1-43115r57'></a><span class='ecrm-0500'>57</span><span class='ectt-0800'>ERROR_THREAD_2:</span>
|
|
<a id='x1-43117r58'></a><span class='ecrm-0500'>58</span><span class='ectt-0800'> kthread_stop(crank_thread);</span>
|
|
<a id='x1-43119r59'></a><span class='ecrm-0500'>59</span><span class='ectt-0800'>ERROR_THREAD_1:</span>
|
|
<a id='x1-43121r60'></a><span class='ecrm-0500'>60</span>
|
|
<a id='x1-43123r61'></a><span class='ecrm-0500'>61</span><span class='ectt-0800'> </span><span id='textcolor1866'><span class='ectt-0800'>return</span></span><span class='ectt-0800'> -1;</span>
|
|
<a id='x1-43125r62'></a><span class='ecrm-0500'>62</span><span class='ectt-0800'>}</span>
|
|
<a id='x1-43127r63'></a><span class='ecrm-0500'>63</span>
|
|
<a id='x1-43129r64'></a><span class='ecrm-0500'>64</span><span id='textcolor1867'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor1868'><span class='ectt-0800'>void</span></span><span class='ectt-0800'> completions_exit(</span><span id='textcolor1869'><span class='ectt-0800'>void</span></span><span class='ectt-0800'>)</span>
|
|
<a id='x1-43131r65'></a><span class='ecrm-0500'>65</span><span class='ectt-0800'>{</span>
|
|
<a id='x1-43133r66'></a><span class='ecrm-0500'>66</span><span class='ectt-0800'> wait_for_completion(&machine.crank_comp);</span>
|
|
<a id='x1-43135r67'></a><span class='ecrm-0500'>67</span><span class='ectt-0800'> wait_for_completion(&machine.flywheel_comp);</span>
|
|
<a id='x1-43137r68'></a><span class='ecrm-0500'>68</span>
|
|
<a id='x1-43139r69'></a><span class='ecrm-0500'>69</span><span class='ectt-0800'> pr_info(</span><span id='textcolor1870'><span class='ectt-0800'>"completions exit</span></span><span id='textcolor1871'><span class='ectt-0800'>\n</span></span><span id='textcolor1872'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>);</span>
|
|
<a id='x1-43141r70'></a><span class='ecrm-0500'>70</span><span class='ectt-0800'>}</span>
|
|
<a id='x1-43143r71'></a><span class='ecrm-0500'>71</span>
|
|
<a id='x1-43145r72'></a><span class='ecrm-0500'>72</span><span class='ectt-0800'>module_init(completions_init);</span>
|
|
<a id='x1-43147r73'></a><span class='ecrm-0500'>73</span><span class='ectt-0800'>module_exit(completions_exit);</span>
|
|
<a id='x1-43149r74'></a><span class='ecrm-0500'>74</span>
|
|
<a id='x1-43151r75'></a><span class='ecrm-0500'>75</span><span class='ectt-0800'>MODULE_DESCRIPTION(</span><span id='textcolor1873'><span class='ectt-0800'>"Completions example"</span></span><span class='ectt-0800'>);</span>
|
|
<a id='x1-43153r76'></a><span class='ecrm-0500'>76</span><span class='ectt-0800'>MODULE_LICENSE(</span><span id='textcolor1874'><span class='ectt-0800'>"GPL"</span></span><span class='ectt-0800'>);</span></pre>
|
|
<!-- l. 1427 --><p class='indent'> The <code> <span class='ectt-1000'>machine</span>
|
|
</code> structure stores the completion states for the two threads. At the exit
|
|
point of each thread the respective completion state is updated, and
|
|
<code> <span class='ectt-1000'>wait_for_completion</span>
|
|
</code> is used by the flywheel thread to ensure that it does not begin prematurely.
|
|
</p><!-- l. 1430 --><p class='indent'> So even though <code> <span class='ectt-1000'>flywheel_thread</span>
|
|
</code> is started first you should notice if you load this module and run
|
|
<code> <span class='ectt-1000'>dmesg</span>
|
|
</code> that turning the crank always happens first because the flywheel thread waits for it
|
|
to complete.
|
|
</p><!-- l. 1432 --><p class='indent'> There are other variations upon the
|
|
<code> <span class='ectt-1000'>wait_for_completion</span>
|
|
</code> function, which include timeouts or being interrupted, but this basic mechanism is
|
|
enough for many common situations without adding a lot of complexity.
|
|
</p><!-- l. 1434 --><p class='noindent'>
|
|
</p>
|
|
<h3 class='sectionHead' id='avoiding-collisions-and-deadlocks'><span class='titlemark'>12 </span> <a id='x1-4400012'></a>Avoiding Collisions and Deadlocks</h3>
|
|
<!-- l. 1436 --><p class='noindent'>If processes running on different CPUs or in different threads try to access the same
|
|
memory, then it is possible that strange things can happen or your system can lock
|
|
up. To avoid this, various types of mutual exclusion kernel functions are available.
|
|
These indicate if a section of code is "locked" or "unlocked" so that simultaneous
|
|
attempts to run it can not happen.
|
|
</p>
|
|
<h4 class='subsectionHead' id='mutex'><span class='titlemark'>12.1 </span> <a id='x1-4500012.1'></a>Mutex</h4>
|
|
<!-- l. 1441 --><p class='noindent'>You can use kernel mutexes (mutual exclusions) in much the same manner that you
|
|
might deploy them in userland. This may be all that is needed to avoid collisions in
|
|
most cases.
|
|
</p><!-- l. 1 --><p class='indent'>
|
|
</p>
|
|
<pre class='fancyvrb' id='fancyvrb57'><a id='x1-45002r1'></a><span class='ecrm-0500'>1</span><span id='textcolor1875'><span class='ectt-0800'>/*</span></span>
|
|
<a id='x1-45004r2'></a><span class='ecrm-0500'>2</span><span id='textcolor1876'><span class='ectt-0800'> * example_mutex.c</span></span>
|
|
<a id='x1-45006r3'></a><span class='ecrm-0500'>3</span><span id='textcolor1877'><span class='ectt-0800'> */</span></span>
|
|
<a id='x1-45008r4'></a><span class='ecrm-0500'>4</span><span id='textcolor1878'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor1879'><span class='ectt-0800'><linux/init.h></span></span>
|
|
<a id='x1-45010r5'></a><span class='ecrm-0500'>5</span><span id='textcolor1880'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor1881'><span class='ectt-0800'><linux/kernel.h></span></span>
|
|
<a id='x1-45012r6'></a><span class='ecrm-0500'>6</span><span id='textcolor1882'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor1883'><span class='ectt-0800'><linux/module.h></span></span>
|
|
<a id='x1-45014r7'></a><span class='ecrm-0500'>7</span><span id='textcolor1884'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor1885'><span class='ectt-0800'><linux/mutex.h></span></span>
|
|
<a id='x1-45016r8'></a><span class='ecrm-0500'>8</span>
|
|
<a id='x1-45018r9'></a><span class='ecrm-0500'>9</span><span id='textcolor1886'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> DEFINE_MUTEX(mymutex);</span>
|
|
<a id='x1-45020r10'></a><span class='ecrm-0500'>10</span>
|
|
<a id='x1-45022r11'></a><span class='ecrm-0500'>11</span><span id='textcolor1887'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor1888'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> example_mutex_init(</span><span id='textcolor1889'><span class='ectt-0800'>void</span></span><span class='ectt-0800'>)</span>
|
|
<a id='x1-45024r12'></a><span class='ecrm-0500'>12</span><span class='ectt-0800'>{</span>
|
|
<a id='x1-45026r13'></a><span class='ecrm-0500'>13</span><span class='ectt-0800'> </span><span id='textcolor1890'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> ret;</span>
|
|
<a id='x1-45028r14'></a><span class='ecrm-0500'>14</span>
|
|
<a id='x1-45030r15'></a><span class='ecrm-0500'>15</span><span class='ectt-0800'> pr_info(</span><span id='textcolor1891'><span class='ectt-0800'>"example_mutex init</span></span><span id='textcolor1892'><span class='ectt-0800'>\n</span></span><span id='textcolor1893'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>);</span>
|
|
<a id='x1-45032r16'></a><span class='ecrm-0500'>16</span>
|
|
<a id='x1-45034r17'></a><span class='ecrm-0500'>17</span><span class='ectt-0800'> ret = mutex_trylock(&mymutex);</span>
|
|
<a id='x1-45036r18'></a><span class='ecrm-0500'>18</span><span class='ectt-0800'> </span><span id='textcolor1894'><span class='ectt-0800'>if</span></span><span class='ectt-0800'> (ret != 0) {</span>
|
|
<a id='x1-45038r19'></a><span class='ecrm-0500'>19</span><span class='ectt-0800'> pr_info(</span><span id='textcolor1895'><span class='ectt-0800'>"mutex is locked</span></span><span id='textcolor1896'><span class='ectt-0800'>\n</span></span><span id='textcolor1897'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>);</span>
|
|
<a id='x1-45040r20'></a><span class='ecrm-0500'>20</span>
|
|
<a id='x1-45042r21'></a><span class='ecrm-0500'>21</span><span class='ectt-0800'> </span><span id='textcolor1898'><span class='ectt-0800'>if</span></span><span class='ectt-0800'> (mutex_is_locked(&mymutex) == 0)</span>
|
|
<a id='x1-45044r22'></a><span class='ecrm-0500'>22</span><span class='ectt-0800'> pr_info(</span><span id='textcolor1899'><span class='ectt-0800'>"The mutex failed to lock!</span></span><span id='textcolor1900'><span class='ectt-0800'>\n</span></span><span id='textcolor1901'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>);</span>
|
|
<a id='x1-45046r23'></a><span class='ecrm-0500'>23</span>
|
|
<a id='x1-45048r24'></a><span class='ecrm-0500'>24</span><span class='ectt-0800'> mutex_unlock(&mymutex);</span>
|
|
<a id='x1-45050r25'></a><span class='ecrm-0500'>25</span><span class='ectt-0800'> pr_info(</span><span id='textcolor1902'><span class='ectt-0800'>"mutex is unlocked</span></span><span id='textcolor1903'><span class='ectt-0800'>\n</span></span><span id='textcolor1904'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>);</span>
|
|
<a id='x1-45052r26'></a><span class='ecrm-0500'>26</span><span class='ectt-0800'> } </span><span id='textcolor1905'><span class='ectt-0800'>else</span></span>
|
|
<a id='x1-45054r27'></a><span class='ecrm-0500'>27</span><span class='ectt-0800'> pr_info(</span><span id='textcolor1906'><span class='ectt-0800'>"Failed to lock</span></span><span id='textcolor1907'><span class='ectt-0800'>\n</span></span><span id='textcolor1908'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>);</span>
|
|
<a id='x1-45056r28'></a><span class='ecrm-0500'>28</span>
|
|
<a id='x1-45058r29'></a><span class='ecrm-0500'>29</span><span class='ectt-0800'> </span><span id='textcolor1909'><span class='ectt-0800'>return</span></span><span class='ectt-0800'> 0;</span>
|
|
<a id='x1-45060r30'></a><span class='ecrm-0500'>30</span><span class='ectt-0800'>}</span>
|
|
<a id='x1-45062r31'></a><span class='ecrm-0500'>31</span>
|
|
<a id='x1-45064r32'></a><span class='ecrm-0500'>32</span><span id='textcolor1910'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor1911'><span class='ectt-0800'>void</span></span><span class='ectt-0800'> example_mutex_exit(</span><span id='textcolor1912'><span class='ectt-0800'>void</span></span><span class='ectt-0800'>)</span>
|
|
<a id='x1-45066r33'></a><span class='ecrm-0500'>33</span><span class='ectt-0800'>{</span>
|
|
<a id='x1-45068r34'></a><span class='ecrm-0500'>34</span><span class='ectt-0800'> pr_info(</span><span id='textcolor1913'><span class='ectt-0800'>"example_mutex exit</span></span><span id='textcolor1914'><span class='ectt-0800'>\n</span></span><span id='textcolor1915'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>);</span>
|
|
<a id='x1-45070r35'></a><span class='ecrm-0500'>35</span><span class='ectt-0800'>}</span>
|
|
<a id='x1-45072r36'></a><span class='ecrm-0500'>36</span>
|
|
<a id='x1-45074r37'></a><span class='ecrm-0500'>37</span><span class='ectt-0800'>module_init(example_mutex_init);</span>
|
|
<a id='x1-45076r38'></a><span class='ecrm-0500'>38</span><span class='ectt-0800'>module_exit(example_mutex_exit);</span>
|
|
<a id='x1-45078r39'></a><span class='ecrm-0500'>39</span>
|
|
<a id='x1-45080r40'></a><span class='ecrm-0500'>40</span><span class='ectt-0800'>MODULE_DESCRIPTION(</span><span id='textcolor1916'><span class='ectt-0800'>"Mutex example"</span></span><span class='ectt-0800'>);</span>
|
|
<a id='x1-45082r41'></a><span class='ecrm-0500'>41</span><span class='ectt-0800'>MODULE_LICENSE(</span><span id='textcolor1917'><span class='ectt-0800'>"GPL"</span></span><span class='ectt-0800'>);</span></pre>
|
|
<!-- l. 1446 --><p class='noindent'>
|
|
</p>
|
|
<h4 class='subsectionHead' id='spinlocks'><span class='titlemark'>12.2 </span> <a id='x1-4600012.2'></a>Spinlocks</h4>
|
|
<!-- l. 1448 --><p class='noindent'>As the name suggests, spinlocks lock up the CPU that the code is running on,
|
|
taking 100% of its resources. Because of this you should only use the spinlock
|
|
|
|
|
|
|
|
mechanism around code which is likely to take no more than a few milliseconds to
|
|
run and so will not noticeably slow anything down from the user’s point of
|
|
view.
|
|
</p><!-- l. 1451 --><p class='indent'> The example here is <span class='obeylines-h'><span class='verb'><span class='ectt-1000'>"irq safe"</span></span></span> in that if interrupts happen during the lock then
|
|
they will not be forgotten and will activate when the unlock happens, using the
|
|
<code> <span class='ectt-1000'>flags</span>
|
|
</code> variable to retain their state.
|
|
</p><!-- l. 1 --><p class='indent'>
|
|
</p>
|
|
<pre class='fancyvrb' id='fancyvrb58'><a id='x1-46003r1'></a><span class='ecrm-0500'>1</span><span id='textcolor1918'><span class='ectt-0800'>/*</span></span>
|
|
<a id='x1-46005r2'></a><span class='ecrm-0500'>2</span><span id='textcolor1919'><span class='ectt-0800'> * example_spinlock.c</span></span>
|
|
<a id='x1-46007r3'></a><span class='ecrm-0500'>3</span><span id='textcolor1920'><span class='ectt-0800'> */</span></span>
|
|
<a id='x1-46009r4'></a><span class='ecrm-0500'>4</span><span id='textcolor1921'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor1922'><span class='ectt-0800'><linux/init.h></span></span>
|
|
<a id='x1-46011r5'></a><span class='ecrm-0500'>5</span><span id='textcolor1923'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor1924'><span class='ectt-0800'><linux/interrupt.h></span></span>
|
|
<a id='x1-46013r6'></a><span class='ecrm-0500'>6</span><span id='textcolor1925'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor1926'><span class='ectt-0800'><linux/kernel.h></span></span>
|
|
<a id='x1-46015r7'></a><span class='ecrm-0500'>7</span><span id='textcolor1927'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor1928'><span class='ectt-0800'><linux/module.h></span></span>
|
|
<a id='x1-46017r8'></a><span class='ecrm-0500'>8</span><span id='textcolor1929'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor1930'><span class='ectt-0800'><linux/spinlock.h></span></span>
|
|
<a id='x1-46019r9'></a><span class='ecrm-0500'>9</span>
|
|
<a id='x1-46021r10'></a><span class='ecrm-0500'>10</span><span id='textcolor1931'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> DEFINE_SPINLOCK(sl_static);</span>
|
|
<a id='x1-46023r11'></a><span class='ecrm-0500'>11</span><span id='textcolor1932'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> spinlock_t sl_dynamic;</span>
|
|
<a id='x1-46025r12'></a><span class='ecrm-0500'>12</span>
|
|
<a id='x1-46027r13'></a><span class='ecrm-0500'>13</span><span id='textcolor1933'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor1934'><span class='ectt-0800'>void</span></span><span class='ectt-0800'> example_spinlock_static(</span><span id='textcolor1935'><span class='ectt-0800'>void</span></span><span class='ectt-0800'>)</span>
|
|
<a id='x1-46029r14'></a><span class='ecrm-0500'>14</span><span class='ectt-0800'>{</span>
|
|
<a id='x1-46031r15'></a><span class='ecrm-0500'>15</span><span class='ectt-0800'> </span><span id='textcolor1936'><span class='ectt-0800'>unsigned</span></span><span class='ectt-0800'> </span><span id='textcolor1937'><span class='ectt-0800'>long</span></span><span class='ectt-0800'> flags;</span>
|
|
<a id='x1-46033r16'></a><span class='ecrm-0500'>16</span>
|
|
<a id='x1-46035r17'></a><span class='ecrm-0500'>17</span><span class='ectt-0800'> spin_lock_irqsave(&sl_static, flags);</span>
|
|
<a id='x1-46037r18'></a><span class='ecrm-0500'>18</span><span class='ectt-0800'> pr_info(</span><span id='textcolor1938'><span class='ectt-0800'>"Locked static spinlock</span></span><span id='textcolor1939'><span class='ectt-0800'>\n</span></span><span id='textcolor1940'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>);</span>
|
|
<a id='x1-46039r19'></a><span class='ecrm-0500'>19</span>
|
|
<a id='x1-46041r20'></a><span class='ecrm-0500'>20</span><span class='ectt-0800'> </span><span id='textcolor1941'><span class='ectt-0800'>/* Do something or other safely. Because this uses 100% CPU time, this</span></span>
|
|
<a id='x1-46043r21'></a><span class='ecrm-0500'>21</span><span id='textcolor1942'><span class='ectt-0800'> * code should take no more than a few milliseconds to run.</span></span>
|
|
<a id='x1-46045r22'></a><span class='ecrm-0500'>22</span><span id='textcolor1943'><span class='ectt-0800'> */</span></span>
|
|
<a id='x1-46047r23'></a><span class='ecrm-0500'>23</span>
|
|
<a id='x1-46049r24'></a><span class='ecrm-0500'>24</span><span class='ectt-0800'> spin_unlock_irqrestore(&sl_static, flags);</span>
|
|
<a id='x1-46051r25'></a><span class='ecrm-0500'>25</span><span class='ectt-0800'> pr_info(</span><span id='textcolor1944'><span class='ectt-0800'>"Unlocked static spinlock</span></span><span id='textcolor1945'><span class='ectt-0800'>\n</span></span><span id='textcolor1946'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>);</span>
|
|
<a id='x1-46053r26'></a><span class='ecrm-0500'>26</span><span class='ectt-0800'>}</span>
|
|
<a id='x1-46055r27'></a><span class='ecrm-0500'>27</span>
|
|
<a id='x1-46057r28'></a><span class='ecrm-0500'>28</span><span id='textcolor1947'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor1948'><span class='ectt-0800'>void</span></span><span class='ectt-0800'> example_spinlock_dynamic(</span><span id='textcolor1949'><span class='ectt-0800'>void</span></span><span class='ectt-0800'>)</span>
|
|
<a id='x1-46059r29'></a><span class='ecrm-0500'>29</span><span class='ectt-0800'>{</span>
|
|
<a id='x1-46061r30'></a><span class='ecrm-0500'>30</span><span class='ectt-0800'> </span><span id='textcolor1950'><span class='ectt-0800'>unsigned</span></span><span class='ectt-0800'> </span><span id='textcolor1951'><span class='ectt-0800'>long</span></span><span class='ectt-0800'> flags;</span>
|
|
<a id='x1-46063r31'></a><span class='ecrm-0500'>31</span>
|
|
<a id='x1-46065r32'></a><span class='ecrm-0500'>32</span><span class='ectt-0800'> spin_lock_init(&sl_dynamic);</span>
|
|
<a id='x1-46067r33'></a><span class='ecrm-0500'>33</span><span class='ectt-0800'> spin_lock_irqsave(&sl_dynamic, flags);</span>
|
|
<a id='x1-46069r34'></a><span class='ecrm-0500'>34</span><span class='ectt-0800'> pr_info(</span><span id='textcolor1952'><span class='ectt-0800'>"Locked dynamic spinlock</span></span><span id='textcolor1953'><span class='ectt-0800'>\n</span></span><span id='textcolor1954'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>);</span>
|
|
<a id='x1-46071r35'></a><span class='ecrm-0500'>35</span>
|
|
<a id='x1-46073r36'></a><span class='ecrm-0500'>36</span><span class='ectt-0800'> </span><span id='textcolor1955'><span class='ectt-0800'>/* Do something or other safely. Because this uses 100% CPU time, this</span></span>
|
|
<a id='x1-46075r37'></a><span class='ecrm-0500'>37</span><span id='textcolor1956'><span class='ectt-0800'> * code should take no more than a few milliseconds to run.</span></span>
|
|
<a id='x1-46077r38'></a><span class='ecrm-0500'>38</span><span id='textcolor1957'><span class='ectt-0800'> */</span></span>
|
|
<a id='x1-46079r39'></a><span class='ecrm-0500'>39</span>
|
|
<a id='x1-46081r40'></a><span class='ecrm-0500'>40</span><span class='ectt-0800'> spin_unlock_irqrestore(&sl_dynamic, flags);</span>
|
|
<a id='x1-46083r41'></a><span class='ecrm-0500'>41</span><span class='ectt-0800'> pr_info(</span><span id='textcolor1958'><span class='ectt-0800'>"Unlocked dynamic spinlock</span></span><span id='textcolor1959'><span class='ectt-0800'>\n</span></span><span id='textcolor1960'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>);</span>
|
|
<a id='x1-46085r42'></a><span class='ecrm-0500'>42</span><span class='ectt-0800'>}</span>
|
|
<a id='x1-46087r43'></a><span class='ecrm-0500'>43</span>
|
|
<a id='x1-46089r44'></a><span class='ecrm-0500'>44</span><span id='textcolor1961'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor1962'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> example_spinlock_init(</span><span id='textcolor1963'><span class='ectt-0800'>void</span></span><span class='ectt-0800'>)</span>
|
|
<a id='x1-46091r45'></a><span class='ecrm-0500'>45</span><span class='ectt-0800'>{</span>
|
|
<a id='x1-46093r46'></a><span class='ecrm-0500'>46</span><span class='ectt-0800'> pr_info(</span><span id='textcolor1964'><span class='ectt-0800'>"example spinlock started</span></span><span id='textcolor1965'><span class='ectt-0800'>\n</span></span><span id='textcolor1966'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>);</span>
|
|
<a id='x1-46095r47'></a><span class='ecrm-0500'>47</span>
|
|
<a id='x1-46097r48'></a><span class='ecrm-0500'>48</span><span class='ectt-0800'> example_spinlock_static();</span>
|
|
<a id='x1-46099r49'></a><span class='ecrm-0500'>49</span><span class='ectt-0800'> example_spinlock_dynamic();</span>
|
|
<a id='x1-46101r50'></a><span class='ecrm-0500'>50</span>
|
|
<a id='x1-46103r51'></a><span class='ecrm-0500'>51</span><span class='ectt-0800'> </span><span id='textcolor1967'><span class='ectt-0800'>return</span></span><span class='ectt-0800'> 0;</span>
|
|
<a id='x1-46105r52'></a><span class='ecrm-0500'>52</span><span class='ectt-0800'>}</span>
|
|
<a id='x1-46107r53'></a><span class='ecrm-0500'>53</span>
|
|
<a id='x1-46109r54'></a><span class='ecrm-0500'>54</span><span id='textcolor1968'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor1969'><span class='ectt-0800'>void</span></span><span class='ectt-0800'> example_spinlock_exit(</span><span id='textcolor1970'><span class='ectt-0800'>void</span></span><span class='ectt-0800'>)</span>
|
|
<a id='x1-46111r55'></a><span class='ecrm-0500'>55</span><span class='ectt-0800'>{</span>
|
|
<a id='x1-46113r56'></a><span class='ecrm-0500'>56</span><span class='ectt-0800'> pr_info(</span><span id='textcolor1971'><span class='ectt-0800'>"example spinlock exit</span></span><span id='textcolor1972'><span class='ectt-0800'>\n</span></span><span id='textcolor1973'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>);</span>
|
|
<a id='x1-46115r57'></a><span class='ecrm-0500'>57</span><span class='ectt-0800'>}</span>
|
|
<a id='x1-46117r58'></a><span class='ecrm-0500'>58</span>
|
|
<a id='x1-46119r59'></a><span class='ecrm-0500'>59</span><span class='ectt-0800'>module_init(example_spinlock_init);</span>
|
|
<a id='x1-46121r60'></a><span class='ecrm-0500'>60</span><span class='ectt-0800'>module_exit(example_spinlock_exit);</span>
|
|
<a id='x1-46123r61'></a><span class='ecrm-0500'>61</span>
|
|
<a id='x1-46125r62'></a><span class='ecrm-0500'>62</span><span class='ectt-0800'>MODULE_DESCRIPTION(</span><span id='textcolor1974'><span class='ectt-0800'>"Spinlock example"</span></span><span class='ectt-0800'>);</span>
|
|
<a id='x1-46127r63'></a><span class='ecrm-0500'>63</span><span class='ectt-0800'>MODULE_LICENSE(</span><span id='textcolor1975'><span class='ectt-0800'>"GPL"</span></span><span class='ectt-0800'>);</span></pre>
|
|
<!-- l. 1455 --><p class='noindent'>
|
|
</p>
|
|
<h4 class='subsectionHead' id='read-and-write-locks'><span class='titlemark'>12.3 </span> <a id='x1-4700012.3'></a>Read and write locks</h4>
|
|
<!-- l. 1457 --><p class='noindent'>Read and write locks are specialised kinds of spinlocks so that you can exclusively
|
|
read from something or write to something. Like the earlier spinlocks example, the
|
|
one below shows an "irq safe" situation in which if other functions were triggered
|
|
from irqs which might also read and write to whatever you are concerned with
|
|
then they would not disrupt the logic. As before it is a good idea to keep
|
|
anything done within the lock as short as possible so that it does not hang up
|
|
the system and cause users to start revolting against the tyranny of your
|
|
module.
|
|
</p><!-- l. 1 --><p class='indent'>
|
|
</p>
|
|
<pre class='fancyvrb' id='fancyvrb59'><a id='x1-47002r1'></a><span class='ecrm-0500'>1</span><span id='textcolor1976'><span class='ectt-0800'>/*</span></span>
|
|
<a id='x1-47004r2'></a><span class='ecrm-0500'>2</span><span id='textcolor1977'><span class='ectt-0800'> * example_rwlock.c</span></span>
|
|
<a id='x1-47006r3'></a><span class='ecrm-0500'>3</span><span id='textcolor1978'><span class='ectt-0800'> */</span></span>
|
|
<a id='x1-47008r4'></a><span class='ecrm-0500'>4</span><span id='textcolor1979'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor1980'><span class='ectt-0800'><linux/interrupt.h></span></span>
|
|
<a id='x1-47010r5'></a><span class='ecrm-0500'>5</span><span id='textcolor1981'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor1982'><span class='ectt-0800'><linux/kernel.h></span></span>
|
|
<a id='x1-47012r6'></a><span class='ecrm-0500'>6</span><span id='textcolor1983'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor1984'><span class='ectt-0800'><linux/module.h></span></span>
|
|
<a id='x1-47014r7'></a><span class='ecrm-0500'>7</span>
|
|
<a id='x1-47016r8'></a><span class='ecrm-0500'>8</span><span id='textcolor1985'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> DEFINE_RWLOCK(myrwlock);</span>
|
|
<a id='x1-47018r9'></a><span class='ecrm-0500'>9</span>
|
|
<a id='x1-47020r10'></a><span class='ecrm-0500'>10</span><span id='textcolor1986'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor1987'><span class='ectt-0800'>void</span></span><span class='ectt-0800'> example_read_lock(</span><span id='textcolor1988'><span class='ectt-0800'>void</span></span><span class='ectt-0800'>)</span>
|
|
<a id='x1-47022r11'></a><span class='ecrm-0500'>11</span><span class='ectt-0800'>{</span>
|
|
<a id='x1-47024r12'></a><span class='ecrm-0500'>12</span><span class='ectt-0800'> </span><span id='textcolor1989'><span class='ectt-0800'>unsigned</span></span><span class='ectt-0800'> </span><span id='textcolor1990'><span class='ectt-0800'>long</span></span><span class='ectt-0800'> flags;</span>
|
|
<a id='x1-47026r13'></a><span class='ecrm-0500'>13</span>
|
|
<a id='x1-47028r14'></a><span class='ecrm-0500'>14</span><span class='ectt-0800'> read_lock_irqsave(&myrwlock, flags);</span>
|
|
<a id='x1-47030r15'></a><span class='ecrm-0500'>15</span><span class='ectt-0800'> pr_info(</span><span id='textcolor1991'><span class='ectt-0800'>"Read Locked</span></span><span id='textcolor1992'><span class='ectt-0800'>\n</span></span><span id='textcolor1993'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>);</span>
|
|
<a id='x1-47032r16'></a><span class='ecrm-0500'>16</span>
|
|
<a id='x1-47034r17'></a><span class='ecrm-0500'>17</span><span class='ectt-0800'> </span><span id='textcolor1994'><span class='ectt-0800'>/* Read from something */</span></span>
|
|
<a id='x1-47036r18'></a><span class='ecrm-0500'>18</span>
|
|
<a id='x1-47038r19'></a><span class='ecrm-0500'>19</span><span class='ectt-0800'> read_unlock_irqrestore(&myrwlock, flags);</span>
|
|
<a id='x1-47040r20'></a><span class='ecrm-0500'>20</span><span class='ectt-0800'> pr_info(</span><span id='textcolor1995'><span class='ectt-0800'>"Read Unlocked</span></span><span id='textcolor1996'><span class='ectt-0800'>\n</span></span><span id='textcolor1997'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>);</span>
|
|
<a id='x1-47042r21'></a><span class='ecrm-0500'>21</span><span class='ectt-0800'>}</span>
|
|
<a id='x1-47044r22'></a><span class='ecrm-0500'>22</span>
|
|
<a id='x1-47046r23'></a><span class='ecrm-0500'>23</span><span id='textcolor1998'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor1999'><span class='ectt-0800'>void</span></span><span class='ectt-0800'> example_write_lock(</span><span id='textcolor2000'><span class='ectt-0800'>void</span></span><span class='ectt-0800'>)</span>
|
|
<a id='x1-47048r24'></a><span class='ecrm-0500'>24</span><span class='ectt-0800'>{</span>
|
|
<a id='x1-47050r25'></a><span class='ecrm-0500'>25</span><span class='ectt-0800'> </span><span id='textcolor2001'><span class='ectt-0800'>unsigned</span></span><span class='ectt-0800'> </span><span id='textcolor2002'><span class='ectt-0800'>long</span></span><span class='ectt-0800'> flags;</span>
|
|
<a id='x1-47052r26'></a><span class='ecrm-0500'>26</span>
|
|
<a id='x1-47054r27'></a><span class='ecrm-0500'>27</span><span class='ectt-0800'> write_lock_irqsave(&myrwlock, flags);</span>
|
|
<a id='x1-47056r28'></a><span class='ecrm-0500'>28</span><span class='ectt-0800'> pr_info(</span><span id='textcolor2003'><span class='ectt-0800'>"Write Locked</span></span><span id='textcolor2004'><span class='ectt-0800'>\n</span></span><span id='textcolor2005'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>);</span>
|
|
<a id='x1-47058r29'></a><span class='ecrm-0500'>29</span>
|
|
<a id='x1-47060r30'></a><span class='ecrm-0500'>30</span><span class='ectt-0800'> </span><span id='textcolor2006'><span class='ectt-0800'>/* Write to something */</span></span>
|
|
<a id='x1-47062r31'></a><span class='ecrm-0500'>31</span>
|
|
<a id='x1-47064r32'></a><span class='ecrm-0500'>32</span><span class='ectt-0800'> write_unlock_irqrestore(&myrwlock, flags);</span>
|
|
<a id='x1-47066r33'></a><span class='ecrm-0500'>33</span><span class='ectt-0800'> pr_info(</span><span id='textcolor2007'><span class='ectt-0800'>"Write Unlocked</span></span><span id='textcolor2008'><span class='ectt-0800'>\n</span></span><span id='textcolor2009'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>);</span>
|
|
<a id='x1-47068r34'></a><span class='ecrm-0500'>34</span><span class='ectt-0800'>}</span>
|
|
<a id='x1-47070r35'></a><span class='ecrm-0500'>35</span>
|
|
<a id='x1-47072r36'></a><span class='ecrm-0500'>36</span><span id='textcolor2010'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor2011'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> example_rwlock_init(</span><span id='textcolor2012'><span class='ectt-0800'>void</span></span><span class='ectt-0800'>)</span>
|
|
<a id='x1-47074r37'></a><span class='ecrm-0500'>37</span><span class='ectt-0800'>{</span>
|
|
<a id='x1-47076r38'></a><span class='ecrm-0500'>38</span><span class='ectt-0800'> pr_info(</span><span id='textcolor2013'><span class='ectt-0800'>"example_rwlock started</span></span><span id='textcolor2014'><span class='ectt-0800'>\n</span></span><span id='textcolor2015'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>);</span>
|
|
<a id='x1-47078r39'></a><span class='ecrm-0500'>39</span>
|
|
<a id='x1-47080r40'></a><span class='ecrm-0500'>40</span><span class='ectt-0800'> example_read_lock();</span>
|
|
<a id='x1-47082r41'></a><span class='ecrm-0500'>41</span><span class='ectt-0800'> example_write_lock();</span>
|
|
<a id='x1-47084r42'></a><span class='ecrm-0500'>42</span>
|
|
<a id='x1-47086r43'></a><span class='ecrm-0500'>43</span><span class='ectt-0800'> </span><span id='textcolor2016'><span class='ectt-0800'>return</span></span><span class='ectt-0800'> 0;</span>
|
|
<a id='x1-47088r44'></a><span class='ecrm-0500'>44</span><span class='ectt-0800'>}</span>
|
|
<a id='x1-47090r45'></a><span class='ecrm-0500'>45</span>
|
|
<a id='x1-47092r46'></a><span class='ecrm-0500'>46</span><span id='textcolor2017'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor2018'><span class='ectt-0800'>void</span></span><span class='ectt-0800'> example_rwlock_exit(</span><span id='textcolor2019'><span class='ectt-0800'>void</span></span><span class='ectt-0800'>)</span>
|
|
<a id='x1-47094r47'></a><span class='ecrm-0500'>47</span><span class='ectt-0800'>{</span>
|
|
<a id='x1-47096r48'></a><span class='ecrm-0500'>48</span><span class='ectt-0800'> pr_info(</span><span id='textcolor2020'><span class='ectt-0800'>"example_rwlock exit</span></span><span id='textcolor2021'><span class='ectt-0800'>\n</span></span><span id='textcolor2022'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>);</span>
|
|
<a id='x1-47098r49'></a><span class='ecrm-0500'>49</span><span class='ectt-0800'>}</span>
|
|
<a id='x1-47100r50'></a><span class='ecrm-0500'>50</span>
|
|
<a id='x1-47102r51'></a><span class='ecrm-0500'>51</span><span class='ectt-0800'>module_init(example_rwlock_init);</span>
|
|
<a id='x1-47104r52'></a><span class='ecrm-0500'>52</span><span class='ectt-0800'>module_exit(example_rwlock_exit);</span>
|
|
<a id='x1-47106r53'></a><span class='ecrm-0500'>53</span>
|
|
<a id='x1-47108r54'></a><span class='ecrm-0500'>54</span><span class='ectt-0800'>MODULE_DESCRIPTION(</span><span id='textcolor2023'><span class='ectt-0800'>"Read/Write locks example"</span></span><span class='ectt-0800'>);</span>
|
|
<a id='x1-47110r55'></a><span class='ecrm-0500'>55</span><span class='ectt-0800'>MODULE_LICENSE(</span><span id='textcolor2024'><span class='ectt-0800'>"GPL"</span></span><span class='ectt-0800'>);</span></pre>
|
|
<!-- l. 1463 --><p class='indent'> Of course, if you know for sure that there are no functions triggered by irqs
|
|
which could possibly interfere with your logic then you can use the simpler
|
|
<code> <span class='ectt-1000'>read_lock(&myrwlock)</span>
|
|
</code> and <code> <span class='ectt-1000'>read_unlock(&myrwlock)</span>
|
|
</code> or the corresponding write functions.
|
|
</p>
|
|
<h4 class='subsectionHead' id='atomic-operations'><span class='titlemark'>12.4 </span> <a id='x1-4800012.4'></a>Atomic operations</h4>
|
|
<!-- l. 1466 --><p class='noindent'>If you are doing simple arithmetic: adding, subtracting or bitwise operations, then
|
|
there is another way in the multi-CPU and multi-hyperthreaded world to stop other
|
|
parts of the system from messing with your mojo. By using atomic operations you
|
|
can be confident that your addition, subtraction or bit flip did actually happen
|
|
and was not overwritten by some other shenanigans. An example is shown
|
|
below.
|
|
</p><!-- l. 1 --><p class='indent'>
|
|
</p>
|
|
<pre class='fancyvrb' id='fancyvrb60'><a id='x1-48002r1'></a><span class='ecrm-0500'>1</span><span id='textcolor2025'><span class='ectt-0800'>/*</span></span>
|
|
<a id='x1-48004r2'></a><span class='ecrm-0500'>2</span><span id='textcolor2026'><span class='ectt-0800'> * example_atomic.c</span></span>
|
|
<a id='x1-48006r3'></a><span class='ecrm-0500'>3</span><span id='textcolor2027'><span class='ectt-0800'> */</span></span>
|
|
<a id='x1-48008r4'></a><span class='ecrm-0500'>4</span><span id='textcolor2028'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor2029'><span class='ectt-0800'><linux/interrupt.h></span></span>
|
|
<a id='x1-48010r5'></a><span class='ecrm-0500'>5</span><span id='textcolor2030'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor2031'><span class='ectt-0800'><linux/kernel.h></span></span>
|
|
<a id='x1-48012r6'></a><span class='ecrm-0500'>6</span><span id='textcolor2032'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor2033'><span class='ectt-0800'><linux/module.h></span></span>
|
|
<a id='x1-48014r7'></a><span class='ecrm-0500'>7</span>
|
|
<a id='x1-48016r8'></a><span class='ecrm-0500'>8</span><span id='textcolor2034'><span class='ectt-0800'>#define BYTE_TO_BINARY_PATTERN "%c%c%c%c%c%c%c%c"</span></span>
|
|
<a id='x1-48018r9'></a><span class='ecrm-0500'>9</span><span id='textcolor2035'><span class='ectt-0800'>#define BYTE_TO_BINARY(byte) \</span></span>
|
|
<a id='x1-48020r10'></a><span class='ecrm-0500'>10</span><span id='textcolor2036'><span class='ectt-0800'> (byte & 0x80 ? </span><span class='tctt-0800'>'</span><span class='ectt-0800'>1</span><span class='tctt-0800'>'</span><span class='ectt-0800'> : </span><span class='tctt-0800'>'</span><span class='ectt-0800'>0</span><span class='tctt-0800'>'</span><span class='ectt-0800'>), (byte & 0x40 ? </span><span class='tctt-0800'>'</span><span class='ectt-0800'>1</span><span class='tctt-0800'>'</span><span class='ectt-0800'> : </span><span class='tctt-0800'>'</span><span class='ectt-0800'>0</span><span class='tctt-0800'>'</span><span class='ectt-0800'>), \</span></span>
|
|
<a id='x1-48022r11'></a><span class='ecrm-0500'>11</span><span id='textcolor2037'><span class='ectt-0800'> (byte & 0x20 ? </span><span class='tctt-0800'>'</span><span class='ectt-0800'>1</span><span class='tctt-0800'>'</span><span class='ectt-0800'> : </span><span class='tctt-0800'>'</span><span class='ectt-0800'>0</span><span class='tctt-0800'>'</span><span class='ectt-0800'>), (byte & 0x10 ? </span><span class='tctt-0800'>'</span><span class='ectt-0800'>1</span><span class='tctt-0800'>'</span><span class='ectt-0800'> : </span><span class='tctt-0800'>'</span><span class='ectt-0800'>0</span><span class='tctt-0800'>'</span><span class='ectt-0800'>), \</span></span>
|
|
<a id='x1-48024r12'></a><span class='ecrm-0500'>12</span><span id='textcolor2038'><span class='ectt-0800'> (byte & 0x08 ? </span><span class='tctt-0800'>'</span><span class='ectt-0800'>1</span><span class='tctt-0800'>'</span><span class='ectt-0800'> : </span><span class='tctt-0800'>'</span><span class='ectt-0800'>0</span><span class='tctt-0800'>'</span><span class='ectt-0800'>), (byte & 0x04 ? </span><span class='tctt-0800'>'</span><span class='ectt-0800'>1</span><span class='tctt-0800'>'</span><span class='ectt-0800'> : </span><span class='tctt-0800'>'</span><span class='ectt-0800'>0</span><span class='tctt-0800'>'</span><span class='ectt-0800'>), \</span></span>
|
|
<a id='x1-48026r13'></a><span class='ecrm-0500'>13</span><span id='textcolor2039'><span class='ectt-0800'> (byte & 0x02 ? </span><span class='tctt-0800'>'</span><span class='ectt-0800'>1</span><span class='tctt-0800'>'</span><span class='ectt-0800'> : </span><span class='tctt-0800'>'</span><span class='ectt-0800'>0</span><span class='tctt-0800'>'</span><span class='ectt-0800'>), (byte & 0x01 ? </span><span class='tctt-0800'>'</span><span class='ectt-0800'>1</span><span class='tctt-0800'>'</span><span class='ectt-0800'> : </span><span class='tctt-0800'>'</span><span class='ectt-0800'>0</span><span class='tctt-0800'>'</span><span class='ectt-0800'>)</span></span>
|
|
<a id='x1-48028r14'></a><span class='ecrm-0500'>14</span>
|
|
<a id='x1-48030r15'></a><span class='ecrm-0500'>15</span><span id='textcolor2040'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor2041'><span class='ectt-0800'>void</span></span><span class='ectt-0800'> atomic_add_subtract(</span><span id='textcolor2042'><span class='ectt-0800'>void</span></span><span class='ectt-0800'>)</span>
|
|
<a id='x1-48032r16'></a><span class='ecrm-0500'>16</span><span class='ectt-0800'>{</span>
|
|
<a id='x1-48034r17'></a><span class='ecrm-0500'>17</span><span class='ectt-0800'> atomic_t debbie;</span>
|
|
<a id='x1-48036r18'></a><span class='ecrm-0500'>18</span><span class='ectt-0800'> atomic_t chris = ATOMIC_INIT(50);</span>
|
|
<a id='x1-48038r19'></a><span class='ecrm-0500'>19</span>
|
|
<a id='x1-48040r20'></a><span class='ecrm-0500'>20</span><span class='ectt-0800'> atomic_set(&debbie, 45);</span>
|
|
<a id='x1-48042r21'></a><span class='ecrm-0500'>21</span>
|
|
<a id='x1-48044r22'></a><span class='ecrm-0500'>22</span><span class='ectt-0800'> </span><span id='textcolor2043'><span class='ectt-0800'>/* subtract one */</span></span>
|
|
<a id='x1-48046r23'></a><span class='ecrm-0500'>23</span><span class='ectt-0800'> atomic_dec(&debbie);</span>
|
|
<a id='x1-48048r24'></a><span class='ecrm-0500'>24</span>
|
|
<a id='x1-48050r25'></a><span class='ecrm-0500'>25</span><span class='ectt-0800'> atomic_add(7, &debbie);</span>
|
|
<a id='x1-48052r26'></a><span class='ecrm-0500'>26</span>
|
|
<a id='x1-48054r27'></a><span class='ecrm-0500'>27</span><span class='ectt-0800'> </span><span id='textcolor2044'><span class='ectt-0800'>/* add one */</span></span>
|
|
<a id='x1-48056r28'></a><span class='ecrm-0500'>28</span><span class='ectt-0800'> atomic_inc(&debbie);</span>
|
|
<a id='x1-48058r29'></a><span class='ecrm-0500'>29</span>
|
|
<a id='x1-48060r30'></a><span class='ecrm-0500'>30</span><span class='ectt-0800'> pr_info(</span><span id='textcolor2045'><span class='ectt-0800'>"chris: %d, debbie: %d</span></span><span id='textcolor2046'><span class='ectt-0800'>\n</span></span><span id='textcolor2047'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>, atomic_read(&chris),</span>
|
|
<a id='x1-48062r31'></a><span class='ecrm-0500'>31</span><span class='ectt-0800'> atomic_read(&debbie));</span>
|
|
<a id='x1-48064r32'></a><span class='ecrm-0500'>32</span><span class='ectt-0800'>}</span>
|
|
<a id='x1-48066r33'></a><span class='ecrm-0500'>33</span>
|
|
<a id='x1-48068r34'></a><span class='ecrm-0500'>34</span><span id='textcolor2048'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor2049'><span class='ectt-0800'>void</span></span><span class='ectt-0800'> atomic_bitwise(</span><span id='textcolor2050'><span class='ectt-0800'>void</span></span><span class='ectt-0800'>)</span>
|
|
<a id='x1-48070r35'></a><span class='ecrm-0500'>35</span><span class='ectt-0800'>{</span>
|
|
<a id='x1-48072r36'></a><span class='ecrm-0500'>36</span><span class='ectt-0800'> </span><span id='textcolor2051'><span class='ectt-0800'>unsigned</span></span><span class='ectt-0800'> </span><span id='textcolor2052'><span class='ectt-0800'>long</span></span><span class='ectt-0800'> word = 0;</span>
|
|
<a id='x1-48074r37'></a><span class='ecrm-0500'>37</span>
|
|
<a id='x1-48076r38'></a><span class='ecrm-0500'>38</span><span class='ectt-0800'> pr_info(</span><span id='textcolor2053'><span class='ectt-0800'>"Bits 0: "</span></span><span class='ectt-0800'> BYTE_TO_BINARY_PATTERN, BYTE_TO_BINARY(word));</span>
|
|
<a id='x1-48078r39'></a><span class='ecrm-0500'>39</span><span class='ectt-0800'> set_bit(3, &word);</span>
|
|
<a id='x1-48080r40'></a><span class='ecrm-0500'>40</span><span class='ectt-0800'> set_bit(5, &word);</span>
|
|
<a id='x1-48082r41'></a><span class='ecrm-0500'>41</span><span class='ectt-0800'> pr_info(</span><span id='textcolor2054'><span class='ectt-0800'>"Bits 1: "</span></span><span class='ectt-0800'> BYTE_TO_BINARY_PATTERN, BYTE_TO_BINARY(word));</span>
|
|
<a id='x1-48084r42'></a><span class='ecrm-0500'>42</span><span class='ectt-0800'> clear_bit(5, &word);</span>
|
|
<a id='x1-48086r43'></a><span class='ecrm-0500'>43</span><span class='ectt-0800'> pr_info(</span><span id='textcolor2055'><span class='ectt-0800'>"Bits 2: "</span></span><span class='ectt-0800'> BYTE_TO_BINARY_PATTERN, BYTE_TO_BINARY(word));</span>
|
|
<a id='x1-48088r44'></a><span class='ecrm-0500'>44</span><span class='ectt-0800'> change_bit(3, &word);</span>
|
|
<a id='x1-48090r45'></a><span class='ecrm-0500'>45</span>
|
|
<a id='x1-48092r46'></a><span class='ecrm-0500'>46</span><span class='ectt-0800'> pr_info(</span><span id='textcolor2056'><span class='ectt-0800'>"Bits 3: "</span></span><span class='ectt-0800'> BYTE_TO_BINARY_PATTERN, BYTE_TO_BINARY(word));</span>
|
|
<a id='x1-48094r47'></a><span class='ecrm-0500'>47</span><span class='ectt-0800'> </span><span id='textcolor2057'><span class='ectt-0800'>if</span></span><span class='ectt-0800'> (test_and_set_bit(3, &word))</span>
|
|
<a id='x1-48096r48'></a><span class='ecrm-0500'>48</span><span class='ectt-0800'> pr_info(</span><span id='textcolor2058'><span class='ectt-0800'>"wrong</span></span><span id='textcolor2059'><span class='ectt-0800'>\n</span></span><span id='textcolor2060'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>);</span>
|
|
<a id='x1-48098r49'></a><span class='ecrm-0500'>49</span><span class='ectt-0800'> pr_info(</span><span id='textcolor2061'><span class='ectt-0800'>"Bits 4: "</span></span><span class='ectt-0800'> BYTE_TO_BINARY_PATTERN, BYTE_TO_BINARY(word));</span>
|
|
<a id='x1-48100r50'></a><span class='ecrm-0500'>50</span>
|
|
<a id='x1-48102r51'></a><span class='ecrm-0500'>51</span><span class='ectt-0800'> word = 255;</span>
|
|
<a id='x1-48104r52'></a><span class='ecrm-0500'>52</span><span class='ectt-0800'> pr_info(</span><span id='textcolor2062'><span class='ectt-0800'>"Bits 5: "</span></span><span class='ectt-0800'> BYTE_TO_BINARY_PATTERN, BYTE_TO_BINARY(word));</span>
|
|
<a id='x1-48106r53'></a><span class='ecrm-0500'>53</span><span class='ectt-0800'>}</span>
|
|
<a id='x1-48108r54'></a><span class='ecrm-0500'>54</span>
|
|
<a id='x1-48110r55'></a><span class='ecrm-0500'>55</span><span id='textcolor2063'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor2064'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> example_atomic_init(</span><span id='textcolor2065'><span class='ectt-0800'>void</span></span><span class='ectt-0800'>)</span>
|
|
<a id='x1-48112r56'></a><span class='ecrm-0500'>56</span><span class='ectt-0800'>{</span>
|
|
<a id='x1-48114r57'></a><span class='ecrm-0500'>57</span><span class='ectt-0800'> pr_info(</span><span id='textcolor2066'><span class='ectt-0800'>"example_atomic started</span></span><span id='textcolor2067'><span class='ectt-0800'>\n</span></span><span id='textcolor2068'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>);</span>
|
|
<a id='x1-48116r58'></a><span class='ecrm-0500'>58</span>
|
|
<a id='x1-48118r59'></a><span class='ecrm-0500'>59</span><span class='ectt-0800'> atomic_add_subtract();</span>
|
|
<a id='x1-48120r60'></a><span class='ecrm-0500'>60</span><span class='ectt-0800'> atomic_bitwise();</span>
|
|
<a id='x1-48122r61'></a><span class='ecrm-0500'>61</span>
|
|
<a id='x1-48124r62'></a><span class='ecrm-0500'>62</span><span class='ectt-0800'> </span><span id='textcolor2069'><span class='ectt-0800'>return</span></span><span class='ectt-0800'> 0;</span>
|
|
<a id='x1-48126r63'></a><span class='ecrm-0500'>63</span><span class='ectt-0800'>}</span>
|
|
<a id='x1-48128r64'></a><span class='ecrm-0500'>64</span>
|
|
<a id='x1-48130r65'></a><span class='ecrm-0500'>65</span><span id='textcolor2070'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor2071'><span class='ectt-0800'>void</span></span><span class='ectt-0800'> example_atomic_exit(</span><span id='textcolor2072'><span class='ectt-0800'>void</span></span><span class='ectt-0800'>)</span>
|
|
<a id='x1-48132r66'></a><span class='ecrm-0500'>66</span><span class='ectt-0800'>{</span>
|
|
<a id='x1-48134r67'></a><span class='ecrm-0500'>67</span><span class='ectt-0800'> pr_info(</span><span id='textcolor2073'><span class='ectt-0800'>"example_atomic exit</span></span><span id='textcolor2074'><span class='ectt-0800'>\n</span></span><span id='textcolor2075'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>);</span>
|
|
<a id='x1-48136r68'></a><span class='ecrm-0500'>68</span><span class='ectt-0800'>}</span>
|
|
<a id='x1-48138r69'></a><span class='ecrm-0500'>69</span>
|
|
<a id='x1-48140r70'></a><span class='ecrm-0500'>70</span><span class='ectt-0800'>module_init(example_atomic_init);</span>
|
|
<a id='x1-48142r71'></a><span class='ecrm-0500'>71</span><span class='ectt-0800'>module_exit(example_atomic_exit);</span>
|
|
<a id='x1-48144r72'></a><span class='ecrm-0500'>72</span>
|
|
<a id='x1-48146r73'></a><span class='ecrm-0500'>73</span><span class='ectt-0800'>MODULE_DESCRIPTION(</span><span id='textcolor2076'><span class='ectt-0800'>"Atomic operations example"</span></span><span class='ectt-0800'>);</span>
|
|
<a id='x1-48148r74'></a><span class='ecrm-0500'>74</span><span class='ectt-0800'>MODULE_LICENSE(</span><span id='textcolor2077'><span class='ectt-0800'>"GPL"</span></span><span class='ectt-0800'>);</span></pre>
|
|
|
|
|
|
|
|
<!-- l. 1472 --><p class='indent'> Before the C11 standard adopts the built-in atomic types, the kernel already
|
|
provided a small set of atomic types by using a bunch of tricky architecture-specific
|
|
codes. Implementing the atomic types by C11 atomics may allow the kernel to throw
|
|
away the architecture-specific codes and letting the kernel code be more friendly to
|
|
the people who understand the standard. But there are some problems, such as the
|
|
memory model of the kernel doesn’t match the model formed by the C11 atomics.
|
|
For further details, see: </p>
|
|
<ul class='itemize1'>
|
|
<li class='itemize'><a href='https://www.kernel.org/doc/Documentation/atomic_t.txt'>kernel documentation of atomic types</a>
|
|
</li>
|
|
<li class='itemize'><a href='https://lwn.net/Articles/691128/'>Time to move to C11 atomics?</a>
|
|
</li>
|
|
<li class='itemize'><a href='https://lwn.net/Articles/698315/'>Atomic usage patterns in the kernel</a></li></ul>
|
|
<!-- l. 1483 --><p class='noindent'>
|
|
</p>
|
|
<h3 class='sectionHead' id='replacing-print-macros'><span class='titlemark'>13 </span> <a id='x1-4900013'></a>Replacing Print Macros</h3>
|
|
<!-- l. 1485 --><p class='noindent'>
|
|
</p>
|
|
<h4 class='subsectionHead' id='replacement'><span class='titlemark'>13.1 </span> <a id='x1-5000013.1'></a>Replacement</h4>
|
|
<!-- l. 1487 --><p class='noindent'>In Section <a href='#x1-80042'>2<!-- tex4ht:ref: sec:using_x --></a>, I said that X Window System and kernel module programming do not
|
|
mix. That is true for developing kernel modules. But in actual use, you want to be
|
|
able to send messages to whichever tty the command to load the module came
|
|
from.
|
|
</p><!-- l. 1491 --><p class='indent'> "tty" is an abbreviation of <span class='ecti-1000'>teletype</span>: originally a combination keyboard-printer
|
|
used to communicate with a Unix system, and today an abstraction for the text
|
|
stream used for a Unix program, whether it is a physical terminal, an xterm on an X
|
|
display, a network connection used with ssh, etc.
|
|
</p><!-- l. 1493 --><p class='indent'> The way this is done is by using current, a pointer to the currently running task,
|
|
to get the current task’s tty structure. Then, we look inside that tty structure to find
|
|
a pointer to a string write function, which we use to write a string to the
|
|
tty.
|
|
</p><!-- l. 1 --><p class='indent'>
|
|
</p>
|
|
<pre class='fancyvrb' id='fancyvrb61'><a id='x1-50002r1'></a><span class='ecrm-0500'>1</span><span id='textcolor2078'><span class='ectt-0800'>/*</span></span>
|
|
<a id='x1-50004r2'></a><span class='ecrm-0500'>2</span><span id='textcolor2079'><span class='ectt-0800'> * print_string.c - Send output to the tty we</span><span class='tctt-0800'>'</span><span class='ectt-0800'>re running on, regardless if</span></span>
|
|
<a id='x1-50006r3'></a><span class='ecrm-0500'>3</span><span id='textcolor2080'><span class='ectt-0800'> * it is through X11, telnet, etc. We do this by printing the string to the</span></span>
|
|
<a id='x1-50008r4'></a><span class='ecrm-0500'>4</span><span id='textcolor2081'><span class='ectt-0800'> * tty associated with the current task.</span></span>
|
|
<a id='x1-50010r5'></a><span class='ecrm-0500'>5</span><span id='textcolor2082'><span class='ectt-0800'> */</span></span>
|
|
<a id='x1-50012r6'></a><span class='ecrm-0500'>6</span><span id='textcolor2083'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor2084'><span class='ectt-0800'><linux/init.h></span></span>
|
|
<a id='x1-50014r7'></a><span class='ecrm-0500'>7</span><span id='textcolor2085'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor2086'><span class='ectt-0800'><linux/kernel.h></span></span>
|
|
<a id='x1-50016r8'></a><span class='ecrm-0500'>8</span><span id='textcolor2087'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor2088'><span class='ectt-0800'><linux/module.h></span></span>
|
|
<a id='x1-50018r9'></a><span class='ecrm-0500'>9</span><span id='textcolor2089'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor2090'><span class='ectt-0800'><linux/sched.h> /* For current */</span></span>
|
|
<a id='x1-50020r10'></a><span class='ecrm-0500'>10</span><span id='textcolor2091'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor2092'><span class='ectt-0800'><linux/tty.h> /* For the tty declarations */</span></span>
|
|
<a id='x1-50022r11'></a><span class='ecrm-0500'>11</span>
|
|
<a id='x1-50024r12'></a><span class='ecrm-0500'>12</span><span id='textcolor2093'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor2094'><span class='ectt-0800'>void</span></span><span class='ectt-0800'> print_string(</span><span id='textcolor2095'><span class='ectt-0800'>char</span></span><span class='ectt-0800'> *str)</span>
|
|
<a id='x1-50026r13'></a><span class='ecrm-0500'>13</span><span class='ectt-0800'>{</span>
|
|
<a id='x1-50028r14'></a><span class='ecrm-0500'>14</span><span class='ectt-0800'> </span><span id='textcolor2096'><span class='ectt-0800'>/* The tty for the current task */</span></span>
|
|
<a id='x1-50030r15'></a><span class='ecrm-0500'>15</span><span class='ectt-0800'> </span><span id='textcolor2097'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> tty_struct *my_tty = get_current_tty();</span>
|
|
<a id='x1-50032r16'></a><span class='ecrm-0500'>16</span>
|
|
<a id='x1-50034r17'></a><span class='ecrm-0500'>17</span><span class='ectt-0800'> </span><span id='textcolor2098'><span class='ectt-0800'>/* If my_tty is NULL, the current task has no tty you can print to (i.e.,</span></span>
|
|
<a id='x1-50036r18'></a><span class='ecrm-0500'>18</span><span id='textcolor2099'><span class='ectt-0800'> * if it is a daemon). If so, there is nothing we can do.</span></span>
|
|
<a id='x1-50038r19'></a><span class='ecrm-0500'>19</span><span id='textcolor2100'><span class='ectt-0800'> */</span></span>
|
|
<a id='x1-50040r20'></a><span class='ecrm-0500'>20</span><span class='ectt-0800'> </span><span id='textcolor2101'><span class='ectt-0800'>if</span></span><span class='ectt-0800'> (my_tty) {</span>
|
|
<a id='x1-50042r21'></a><span class='ecrm-0500'>21</span><span class='ectt-0800'> </span><span id='textcolor2102'><span class='ectt-0800'>const</span></span><span class='ectt-0800'> </span><span id='textcolor2103'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> tty_operations *ttyops = my_tty->driver->ops;</span>
|
|
<a id='x1-50044r22'></a><span class='ecrm-0500'>22</span><span class='ectt-0800'> </span><span id='textcolor2104'><span class='ectt-0800'>/* my_tty->driver is a struct which holds the tty</span><span class='tctt-0800'>'</span><span class='ectt-0800'>s functions,</span></span>
|
|
<a id='x1-50046r23'></a><span class='ecrm-0500'>23</span><span id='textcolor2105'><span class='ectt-0800'> * one of which (write) is used to write strings to the tty.</span></span>
|
|
<a id='x1-50048r24'></a><span class='ecrm-0500'>24</span><span id='textcolor2106'><span class='ectt-0800'> * It can be used to take a string either from the user</span><span class='tctt-0800'>'</span><span class='ectt-0800'>s or</span></span>
|
|
<a id='x1-50050r25'></a><span class='ecrm-0500'>25</span><span id='textcolor2107'><span class='ectt-0800'> * kernel</span><span class='tctt-0800'>'</span><span class='ectt-0800'>s memory segment.</span></span>
|
|
<a id='x1-50052r26'></a><span class='ecrm-0500'>26</span><span id='textcolor2108'><span class='ectt-0800'> *</span></span>
|
|
<a id='x1-50054r27'></a><span class='ecrm-0500'>27</span><span id='textcolor2109'><span class='ectt-0800'> * The function</span><span class='tctt-0800'>'</span><span class='ectt-0800'>s 1st parameter is the tty to write to, because the</span></span>
|
|
<a id='x1-50056r28'></a><span class='ecrm-0500'>28</span><span id='textcolor2110'><span class='ectt-0800'> * same function would normally be used for all tty</span><span class='tctt-0800'>'</span><span class='ectt-0800'>s of a certain</span></span>
|
|
<a id='x1-50058r29'></a><span class='ecrm-0500'>29</span><span id='textcolor2111'><span class='ectt-0800'> * type.</span></span>
|
|
<a id='x1-50060r30'></a><span class='ecrm-0500'>30</span><span id='textcolor2112'><span class='ectt-0800'> * The 2nd parameter is a pointer to a string.</span></span>
|
|
<a id='x1-50062r31'></a><span class='ecrm-0500'>31</span><span id='textcolor2113'><span class='ectt-0800'> * The 3rd parameter is the length of the string.</span></span>
|
|
<a id='x1-50064r32'></a><span class='ecrm-0500'>32</span><span id='textcolor2114'><span class='ectt-0800'> *</span></span>
|
|
<a id='x1-50066r33'></a><span class='ecrm-0500'>33</span><span id='textcolor2115'><span class='ectt-0800'> * As you will see below, sometimes it</span><span class='tctt-0800'>'</span><span class='ectt-0800'>s necessary to use</span></span>
|
|
<a id='x1-50068r34'></a><span class='ecrm-0500'>34</span><span id='textcolor2116'><span class='ectt-0800'> * preprocessor stuff to create code that works for different</span></span>
|
|
<a id='x1-50070r35'></a><span class='ecrm-0500'>35</span><span id='textcolor2117'><span class='ectt-0800'> * kernel versions. The (naive) approach we</span><span class='tctt-0800'>'</span><span class='ectt-0800'>ve taken here does not</span></span>
|
|
<a id='x1-50072r36'></a><span class='ecrm-0500'>36</span><span id='textcolor2118'><span class='ectt-0800'> * scale well. The right way to deal with this is described in</span></span>
|
|
<a id='x1-50074r37'></a><span class='ecrm-0500'>37</span><span id='textcolor2119'><span class='ectt-0800'> * section 2 of</span></span>
|
|
<a id='x1-50076r38'></a><span class='ecrm-0500'>38</span><span id='textcolor2120'><span class='ectt-0800'> * linux/Documentation/SubmittingPatches</span></span>
|
|
<a id='x1-50078r39'></a><span class='ecrm-0500'>39</span><span id='textcolor2121'><span class='ectt-0800'> */</span></span>
|
|
<a id='x1-50080r40'></a><span class='ecrm-0500'>40</span><span class='ectt-0800'> (ttyops->write)(my_tty, </span><span id='textcolor2122'><span class='ectt-0800'>/* The tty itself */</span></span>
|
|
<a id='x1-50082r41'></a><span class='ecrm-0500'>41</span><span class='ectt-0800'> str, </span><span id='textcolor2123'><span class='ectt-0800'>/* String */</span></span>
|
|
<a id='x1-50084r42'></a><span class='ecrm-0500'>42</span><span class='ectt-0800'> strlen(str)); </span><span id='textcolor2124'><span class='ectt-0800'>/* Length */</span></span>
|
|
<a id='x1-50086r43'></a><span class='ecrm-0500'>43</span>
|
|
<a id='x1-50088r44'></a><span class='ecrm-0500'>44</span><span class='ectt-0800'> </span><span id='textcolor2125'><span class='ectt-0800'>/* ttys were originally hardware devices, which (usually) strictly</span></span>
|
|
<a id='x1-50090r45'></a><span class='ecrm-0500'>45</span><span id='textcolor2126'><span class='ectt-0800'> * followed the ASCII standard. In ASCII, to move to a new line you</span></span>
|
|
<a id='x1-50092r46'></a><span class='ecrm-0500'>46</span><span id='textcolor2127'><span class='ectt-0800'> * need two characters, a carriage return and a line feed. On Unix,</span></span>
|
|
<a id='x1-50094r47'></a><span class='ecrm-0500'>47</span><span id='textcolor2128'><span class='ectt-0800'> * the ASCII line feed is used for both purposes - so we can not</span></span>
|
|
<a id='x1-50096r48'></a><span class='ecrm-0500'>48</span><span id='textcolor2129'><span class='ectt-0800'> * just use \n, because it would not have a carriage return and the</span></span>
|
|
<a id='x1-50098r49'></a><span class='ecrm-0500'>49</span><span id='textcolor2130'><span class='ectt-0800'> * next line will start at the column right after the line feed.</span></span>
|
|
<a id='x1-50100r50'></a><span class='ecrm-0500'>50</span><span id='textcolor2131'><span class='ectt-0800'> *</span></span>
|
|
<a id='x1-50102r51'></a><span class='ecrm-0500'>51</span><span id='textcolor2132'><span class='ectt-0800'> * This is why text files are different between Unix and MS Windows.</span></span>
|
|
<a id='x1-50104r52'></a><span class='ecrm-0500'>52</span><span id='textcolor2133'><span class='ectt-0800'> * In CP/M and derivatives, like MS-DOS and MS Windows, the ASCII</span></span>
|
|
<a id='x1-50106r53'></a><span class='ecrm-0500'>53</span><span id='textcolor2134'><span class='ectt-0800'> * standard was strictly adhered to, and therefore a newline requirs</span></span>
|
|
<a id='x1-50108r54'></a><span class='ecrm-0500'>54</span><span id='textcolor2135'><span class='ectt-0800'> * both a LF and a CR.</span></span>
|
|
<a id='x1-50110r55'></a><span class='ecrm-0500'>55</span><span id='textcolor2136'><span class='ectt-0800'> */</span></span>
|
|
<a id='x1-50112r56'></a><span class='ecrm-0500'>56</span><span class='ectt-0800'> (ttyops->write)(my_tty, </span><span id='textcolor2137'><span class='ectt-0800'>"</span></span><span id='textcolor2138'><span class='ectt-0800'>\015\012</span></span><span id='textcolor2139'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>, 2);</span>
|
|
<a id='x1-50114r57'></a><span class='ecrm-0500'>57</span><span class='ectt-0800'> }</span>
|
|
<a id='x1-50116r58'></a><span class='ecrm-0500'>58</span><span class='ectt-0800'>}</span>
|
|
<a id='x1-50118r59'></a><span class='ecrm-0500'>59</span>
|
|
<a id='x1-50120r60'></a><span class='ecrm-0500'>60</span><span id='textcolor2140'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor2141'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> __init print_string_init(</span><span id='textcolor2142'><span class='ectt-0800'>void</span></span><span class='ectt-0800'>)</span>
|
|
<a id='x1-50122r61'></a><span class='ecrm-0500'>61</span><span class='ectt-0800'>{</span>
|
|
<a id='x1-50124r62'></a><span class='ecrm-0500'>62</span><span class='ectt-0800'> print_string(</span><span id='textcolor2143'><span class='ectt-0800'>"The module has been inserted. Hello world!"</span></span><span class='ectt-0800'>);</span>
|
|
<a id='x1-50126r63'></a><span class='ecrm-0500'>63</span><span class='ectt-0800'> </span><span id='textcolor2144'><span class='ectt-0800'>return</span></span><span class='ectt-0800'> 0;</span>
|
|
<a id='x1-50128r64'></a><span class='ecrm-0500'>64</span><span class='ectt-0800'>}</span>
|
|
<a id='x1-50130r65'></a><span class='ecrm-0500'>65</span>
|
|
<a id='x1-50132r66'></a><span class='ecrm-0500'>66</span><span id='textcolor2145'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor2146'><span class='ectt-0800'>void</span></span><span class='ectt-0800'> __exit print_string_exit(</span><span id='textcolor2147'><span class='ectt-0800'>void</span></span><span class='ectt-0800'>)</span>
|
|
<a id='x1-50134r67'></a><span class='ecrm-0500'>67</span><span class='ectt-0800'>{</span>
|
|
<a id='x1-50136r68'></a><span class='ecrm-0500'>68</span><span class='ectt-0800'> print_string(</span><span id='textcolor2148'><span class='ectt-0800'>"The module has been removed. Farewell world!"</span></span><span class='ectt-0800'>);</span>
|
|
<a id='x1-50138r69'></a><span class='ecrm-0500'>69</span><span class='ectt-0800'>}</span>
|
|
<a id='x1-50140r70'></a><span class='ecrm-0500'>70</span>
|
|
<a id='x1-50142r71'></a><span class='ecrm-0500'>71</span><span class='ectt-0800'>module_init(print_string_init);</span>
|
|
<a id='x1-50144r72'></a><span class='ecrm-0500'>72</span><span class='ectt-0800'>module_exit(print_string_exit);</span>
|
|
<a id='x1-50146r73'></a><span class='ecrm-0500'>73</span>
|
|
<a id='x1-50148r74'></a><span class='ecrm-0500'>74</span><span class='ectt-0800'>MODULE_LICENSE(</span><span id='textcolor2149'><span class='ectt-0800'>"GPL"</span></span><span class='ectt-0800'>);</span></pre>
|
|
|
|
|
|
|
|
<!-- l. 1498 --><p class='noindent'>
|
|
</p>
|
|
<h4 class='subsectionHead' id='flashing-keyboard-leds'><span class='titlemark'>13.2 </span> <a id='x1-5100013.2'></a>Flashing keyboard LEDs</h4>
|
|
<!-- l. 1500 --><p class='noindent'>In certain conditions, you may desire a simpler and more direct way to communicate
|
|
to the external world. Flashing keyboard LEDs can be such a solution: It is an
|
|
immediate way to attract attention or to display a status condition. Keyboard LEDs
|
|
are present on every hardware, they are always visible, they do not need any setup,
|
|
and their use is rather simple and non-intrusive, compared to writing to a tty or a
|
|
file.
|
|
</p><!-- l. 1504 --><p class='indent'> From v4.14 to v4.15, the timer API made a series of changes
|
|
to improve memory safety. A buffer overflow in the area of a
|
|
<code> <span class='ectt-1000'>timer_list</span>
|
|
</code> structure may be able to overwrite the
|
|
<code> <span class='ectt-1000'>function</span>
|
|
</code> and <code> <span class='ectt-1000'>data</span>
|
|
</code> fields, providing the attacker with a way to use return-object programming (ROP)
|
|
to call arbitrary functions within the kernel. Also, the function prototype of the callback,
|
|
containing a <code> <span id='textcolor2150'><span class='ectt-1000'>unsigned</span></span><span class='ectt-1000'> </span><span id='textcolor2151'><span class='ectt-1000'>long</span></span>
|
|
</code> argument, will prevent work from any type checking. Furthermore, the function prototype
|
|
with <code> <span id='textcolor2152'><span class='ectt-1000'>unsigned</span></span><span class='ectt-1000'> </span><span id='textcolor2153'><span class='ectt-1000'>long</span></span>
|
|
</code> argument may be an obstacle to the <span class='ecti-1000'>control-flow integrity</span>. Thus, it is better
|
|
to use a unique prototype to separate from the cluster that takes an
|
|
<code> <span id='textcolor2154'><span class='ectt-1000'>unsigned</span></span><span class='ectt-1000'> </span><span id='textcolor2155'><span class='ectt-1000'>long</span></span>
|
|
</code> argument. The timer callback should be passed a pointer to the
|
|
<code> <span class='ectt-1000'>timer_list</span>
|
|
</code> structure rather than an <code> <span id='textcolor2156'><span class='ectt-1000'>unsigned</span></span><span class='ectt-1000'> </span><span id='textcolor2157'><span class='ectt-1000'>long</span></span>
|
|
</code> argument. Then, it wraps all the information the callback needs, including the
|
|
<code> <span class='ectt-1000'>timer_list</span>
|
|
</code> structure, into a larger structure, and it can use the
|
|
<code> <span class='ectt-1000'>container_of</span>
|
|
</code> macro instead of the <code> <span id='textcolor2158'><span class='ectt-1000'>unsigned</span></span><span class='ectt-1000'> </span><span id='textcolor2159'><span class='ectt-1000'>long</span></span>
|
|
</code> value.
|
|
</p><!-- l. 1512 --><p class='indent'> Before Linux v4.14, <code> <span class='ectt-1000'>setup_timer</span>
|
|
</code> was used to initialize the timer and the
|
|
<code> <span class='ectt-1000'>timer_list</span>
|
|
</code> structure looked like:
|
|
</p>
|
|
<pre class='fancyvrb' id='fancyvrb62'><a id='x1-51025r1'></a><span class='ecrm-0500'>1</span><span id='textcolor2160'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> timer_list {</span>
|
|
<a id='x1-51027r2'></a><span class='ecrm-0500'>2</span><span class='ectt-0800'> </span><span id='textcolor2161'><span class='ectt-0800'>unsigned</span></span><span class='ectt-0800'> </span><span id='textcolor2162'><span class='ectt-0800'>long</span></span><span class='ectt-0800'> expires;</span>
|
|
<a id='x1-51029r3'></a><span class='ecrm-0500'>3</span><span class='ectt-0800'> </span><span id='textcolor2163'><span class='ectt-0800'>void</span></span><span class='ectt-0800'> (*function)(</span><span id='textcolor2164'><span class='ectt-0800'>unsigned</span></span><span class='ectt-0800'> </span><span id='textcolor2165'><span class='ectt-0800'>long</span></span><span class='ectt-0800'>);</span>
|
|
<a id='x1-51031r4'></a><span class='ecrm-0500'>4</span><span class='ectt-0800'> </span><span id='textcolor2166'><span class='ectt-0800'>unsigned</span></span><span class='ectt-0800'> </span><span id='textcolor2167'><span class='ectt-0800'>long</span></span><span class='ectt-0800'> data;</span>
|
|
<a id='x1-51033r5'></a><span class='ecrm-0500'>5</span><span class='ectt-0800'> u32 flags;</span>
|
|
<a id='x1-51035r6'></a><span class='ecrm-0500'>6</span><span class='ectt-0800'> </span><span id='textcolor2168'><span class='ectt-0800'>/* ... */</span></span>
|
|
<a id='x1-51037r7'></a><span class='ecrm-0500'>7</span><span class='ectt-0800'>};</span>
|
|
<a id='x1-51039r8'></a><span class='ecrm-0500'>8</span>
|
|
<a id='x1-51041r9'></a><span class='ecrm-0500'>9</span><span id='textcolor2169'><span class='ectt-0800'>void</span></span><span class='ectt-0800'> setup_timer(</span><span id='textcolor2170'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> timer_list *timer, </span><span id='textcolor2171'><span class='ectt-0800'>void</span></span><span class='ectt-0800'> (*callback)(</span><span id='textcolor2172'><span class='ectt-0800'>unsigned</span></span><span class='ectt-0800'> </span><span id='textcolor2173'><span class='ectt-0800'>long</span></span><span class='ectt-0800'>),</span>
|
|
<a id='x1-51043r10'></a><span class='ecrm-0500'>10</span><span class='ectt-0800'> </span><span id='textcolor2174'><span class='ectt-0800'>unsigned</span></span><span class='ectt-0800'> </span><span id='textcolor2175'><span class='ectt-0800'>long</span></span><span class='ectt-0800'> data);</span></pre>
|
|
<!-- l. 1526 --><p class='indent'> Since Linux v4.14, <code> <span class='ectt-1000'>timer_setup</span>
|
|
</code> is adopted and the kernel step by step converting to
|
|
<code> <span class='ectt-1000'>timer_setup</span>
|
|
</code> from <code> <span class='ectt-1000'>setup_timer</span>
|
|
</code>. One of the reasons why API was changed is it need to coexist with the old version interface.
|
|
Moreover, the <code> <span class='ectt-1000'>timer_setup</span>
|
|
|
|
|
|
|
|
</code> was implemented by <code> <span class='ectt-1000'>setup_timer</span>
|
|
</code> at first.
|
|
</p>
|
|
<pre class='fancyvrb' id='fancyvrb63'><a id='x1-51052r1'></a><span class='ecrm-0500'>1</span><span id='textcolor2176'><span class='ectt-0800'>void</span></span><span class='ectt-0800'> timer_setup(</span><span id='textcolor2177'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> timer_list *timer,</span>
|
|
<a id='x1-51054r2'></a><span class='ecrm-0500'>2</span><span class='ectt-0800'> </span><span id='textcolor2178'><span class='ectt-0800'>void</span></span><span class='ectt-0800'> (*callback)(</span><span id='textcolor2179'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> timer_list *), </span><span id='textcolor2180'><span class='ectt-0800'>unsigned</span></span><span class='ectt-0800'> </span><span id='textcolor2181'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> flags);</span></pre>
|
|
<!-- l. 1534 --><p class='indent'> The <code> <span class='ectt-1000'>setup_timer</span>
|
|
</code> was then removed since v4.15. As a result, the
|
|
<code> <span class='ectt-1000'>timer_list</span>
|
|
</code> structure had changed to the following.
|
|
</p>
|
|
<pre class='fancyvrb' id='fancyvrb64'><a id='x1-51064r1'></a><span class='ecrm-0500'>1</span><span id='textcolor2182'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> timer_list {</span>
|
|
<a id='x1-51066r2'></a><span class='ecrm-0500'>2</span><span class='ectt-0800'> </span><span id='textcolor2183'><span class='ectt-0800'>unsigned</span></span><span class='ectt-0800'> </span><span id='textcolor2184'><span class='ectt-0800'>long</span></span><span class='ectt-0800'> expires;</span>
|
|
<a id='x1-51068r3'></a><span class='ecrm-0500'>3</span><span class='ectt-0800'> </span><span id='textcolor2185'><span class='ectt-0800'>void</span></span><span class='ectt-0800'> (*function)(</span><span id='textcolor2186'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> timer_list *);</span>
|
|
<a id='x1-51070r4'></a><span class='ecrm-0500'>4</span><span class='ectt-0800'> u32 flags;</span>
|
|
<a id='x1-51072r5'></a><span class='ecrm-0500'>5</span><span class='ectt-0800'> </span><span id='textcolor2187'><span class='ectt-0800'>/* ... */</span></span>
|
|
<a id='x1-51074r6'></a><span class='ecrm-0500'>6</span><span class='ectt-0800'>};</span></pre>
|
|
<!-- l. 1545 --><p class='indent'> The following source code illustrates a minimal kernel module which, when
|
|
loaded, starts blinking the keyboard LEDs until it is unloaded.
|
|
</p><!-- l. 1 --><p class='indent'>
|
|
</p>
|
|
<pre class='fancyvrb' id='fancyvrb65'><a id='x1-51076r1'></a><span class='ecrm-0500'>1</span><span id='textcolor2188'><span class='ectt-0800'>/*</span></span>
|
|
<a id='x1-51078r2'></a><span class='ecrm-0500'>2</span><span id='textcolor2189'><span class='ectt-0800'> * kbleds.c - Blink keyboard leds until the module is unloaded.</span></span>
|
|
<a id='x1-51080r3'></a><span class='ecrm-0500'>3</span><span id='textcolor2190'><span class='ectt-0800'> */</span></span>
|
|
<a id='x1-51082r4'></a><span class='ecrm-0500'>4</span>
|
|
<a id='x1-51084r5'></a><span class='ecrm-0500'>5</span><span id='textcolor2191'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor2192'><span class='ectt-0800'><linux/init.h></span></span>
|
|
<a id='x1-51086r6'></a><span class='ecrm-0500'>6</span><span id='textcolor2193'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor2194'><span class='ectt-0800'><linux/kd.h> /* For KDSETLED */</span></span>
|
|
<a id='x1-51088r7'></a><span class='ecrm-0500'>7</span><span id='textcolor2195'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor2196'><span class='ectt-0800'><linux/module.h></span></span>
|
|
<a id='x1-51090r8'></a><span class='ecrm-0500'>8</span><span id='textcolor2197'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor2198'><span class='ectt-0800'><linux/tty.h> /* For tty_struct */</span></span>
|
|
<a id='x1-51092r9'></a><span class='ecrm-0500'>9</span><span id='textcolor2199'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor2200'><span class='ectt-0800'><linux/vt.h> /* For MAX_NR_CONSOLES */</span></span>
|
|
<a id='x1-51094r10'></a><span class='ecrm-0500'>10</span><span id='textcolor2201'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor2202'><span class='ectt-0800'><linux/vt_kern.h> /* for fg_console */</span></span>
|
|
<a id='x1-51096r11'></a><span class='ecrm-0500'>11</span><span id='textcolor2203'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor2204'><span class='ectt-0800'><linux/console_struct.h> /* For vc_cons */</span></span>
|
|
<a id='x1-51098r12'></a><span class='ecrm-0500'>12</span>
|
|
<a id='x1-51100r13'></a><span class='ecrm-0500'>13</span><span class='ectt-0800'>MODULE_DESCRIPTION(</span><span id='textcolor2205'><span class='ectt-0800'>"Example module illustrating the use of Keyboard LEDs."</span></span><span class='ectt-0800'>);</span>
|
|
<a id='x1-51102r14'></a><span class='ecrm-0500'>14</span>
|
|
<a id='x1-51104r15'></a><span class='ecrm-0500'>15</span><span id='textcolor2206'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor2207'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> timer_list my_timer;</span>
|
|
<a id='x1-51106r16'></a><span class='ecrm-0500'>16</span><span id='textcolor2208'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor2209'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> tty_driver *my_driver;</span>
|
|
<a id='x1-51108r17'></a><span class='ecrm-0500'>17</span><span id='textcolor2210'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor2211'><span class='ectt-0800'>unsigned</span></span><span class='ectt-0800'> </span><span id='textcolor2212'><span class='ectt-0800'>long</span></span><span class='ectt-0800'> kbledstatus = 0;</span>
|
|
<a id='x1-51110r18'></a><span class='ecrm-0500'>18</span>
|
|
<a id='x1-51112r19'></a><span class='ecrm-0500'>19</span><span id='textcolor2213'><span class='ectt-0800'>#define BLINK_DELAY HZ / 5</span></span>
|
|
<a id='x1-51114r20'></a><span class='ecrm-0500'>20</span><span id='textcolor2214'><span class='ectt-0800'>#define ALL_LEDS_ON 0x07</span></span>
|
|
<a id='x1-51116r21'></a><span class='ecrm-0500'>21</span><span id='textcolor2215'><span class='ectt-0800'>#define RESTORE_LEDS 0xFF</span></span>
|
|
<a id='x1-51118r22'></a><span class='ecrm-0500'>22</span>
|
|
<a id='x1-51120r23'></a><span class='ecrm-0500'>23</span><span id='textcolor2216'><span class='ectt-0800'>/* Function my_timer_func blinks the keyboard LEDs periodically by invoking</span></span>
|
|
<a id='x1-51122r24'></a><span class='ecrm-0500'>24</span><span id='textcolor2217'><span class='ectt-0800'> * command KDSETLED of ioctl() on the keyboard driver. To learn more on virtual</span></span>
|
|
<a id='x1-51124r25'></a><span class='ecrm-0500'>25</span><span id='textcolor2218'><span class='ectt-0800'> * terminal ioctl operations, please see file:</span></span>
|
|
<a id='x1-51126r26'></a><span class='ecrm-0500'>26</span><span id='textcolor2219'><span class='ectt-0800'> * drivers/tty/vt/vt_ioctl.c, function vt_ioctl().</span></span>
|
|
<a id='x1-51128r27'></a><span class='ecrm-0500'>27</span><span id='textcolor2220'><span class='ectt-0800'> *</span></span>
|
|
<a id='x1-51130r28'></a><span class='ecrm-0500'>28</span><span id='textcolor2221'><span class='ectt-0800'> * The argument to KDSETLED is alternatively set to 7 (thus causing the led</span></span>
|
|
<a id='x1-51132r29'></a><span class='ecrm-0500'>29</span><span id='textcolor2222'><span class='ectt-0800'> * mode to be set to LED_SHOW_IOCTL, and all the leds are lit) and to 0xFF</span></span>
|
|
<a id='x1-51134r30'></a><span class='ecrm-0500'>30</span><span id='textcolor2223'><span class='ectt-0800'> * (any value above 7 switches back the led mode to LED_SHOW_FLAGS, thus</span></span>
|
|
<a id='x1-51136r31'></a><span class='ecrm-0500'>31</span><span id='textcolor2224'><span class='ectt-0800'> * the LEDs reflect the actual keyboard status). To learn more on this,</span></span>
|
|
<a id='x1-51138r32'></a><span class='ecrm-0500'>32</span><span id='textcolor2225'><span class='ectt-0800'> * please see file: drivers/tty/vt/keyboard.c, function setledstate().</span></span>
|
|
<a id='x1-51140r33'></a><span class='ecrm-0500'>33</span><span id='textcolor2226'><span class='ectt-0800'> */</span></span>
|
|
<a id='x1-51142r34'></a><span class='ecrm-0500'>34</span><span id='textcolor2227'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor2228'><span class='ectt-0800'>void</span></span><span class='ectt-0800'> my_timer_func(</span><span id='textcolor2229'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> timer_list *unused)</span>
|
|
<a id='x1-51144r35'></a><span class='ecrm-0500'>35</span><span class='ectt-0800'>{</span>
|
|
<a id='x1-51146r36'></a><span class='ecrm-0500'>36</span><span class='ectt-0800'> </span><span id='textcolor2230'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> tty_struct *t = vc_cons[fg_console].d->port.tty;</span>
|
|
<a id='x1-51148r37'></a><span class='ecrm-0500'>37</span>
|
|
<a id='x1-51150r38'></a><span class='ecrm-0500'>38</span><span class='ectt-0800'> </span><span id='textcolor2231'><span class='ectt-0800'>if</span></span><span class='ectt-0800'> (kbledstatus == ALL_LEDS_ON)</span>
|
|
<a id='x1-51152r39'></a><span class='ecrm-0500'>39</span><span class='ectt-0800'> kbledstatus = RESTORE_LEDS;</span>
|
|
<a id='x1-51154r40'></a><span class='ecrm-0500'>40</span><span class='ectt-0800'> </span><span id='textcolor2232'><span class='ectt-0800'>else</span></span>
|
|
<a id='x1-51156r41'></a><span class='ecrm-0500'>41</span><span class='ectt-0800'> kbledstatus = ALL_LEDS_ON;</span>
|
|
<a id='x1-51158r42'></a><span class='ecrm-0500'>42</span>
|
|
<a id='x1-51160r43'></a><span class='ecrm-0500'>43</span><span class='ectt-0800'> (my_driver->ops->ioctl)(t, KDSETLED, kbledstatus);</span>
|
|
<a id='x1-51162r44'></a><span class='ecrm-0500'>44</span>
|
|
<a id='x1-51164r45'></a><span class='ecrm-0500'>45</span><span class='ectt-0800'> my_timer.expires = jiffies + BLINK_DELAY;</span>
|
|
<a id='x1-51166r46'></a><span class='ecrm-0500'>46</span><span class='ectt-0800'> add_timer(&my_timer);</span>
|
|
<a id='x1-51168r47'></a><span class='ecrm-0500'>47</span><span class='ectt-0800'>}</span>
|
|
<a id='x1-51170r48'></a><span class='ecrm-0500'>48</span>
|
|
<a id='x1-51172r49'></a><span class='ecrm-0500'>49</span><span id='textcolor2233'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor2234'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> __init kbleds_init(</span><span id='textcolor2235'><span class='ectt-0800'>void</span></span><span class='ectt-0800'>)</span>
|
|
<a id='x1-51174r50'></a><span class='ecrm-0500'>50</span><span class='ectt-0800'>{</span>
|
|
<a id='x1-51176r51'></a><span class='ecrm-0500'>51</span><span class='ectt-0800'> </span><span id='textcolor2236'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> i;</span>
|
|
<a id='x1-51178r52'></a><span class='ecrm-0500'>52</span>
|
|
<a id='x1-51180r53'></a><span class='ecrm-0500'>53</span><span class='ectt-0800'> pr_info(</span><span id='textcolor2237'><span class='ectt-0800'>"kbleds: loading</span></span><span id='textcolor2238'><span class='ectt-0800'>\n</span></span><span id='textcolor2239'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>);</span>
|
|
<a id='x1-51182r54'></a><span class='ecrm-0500'>54</span><span class='ectt-0800'> pr_info(</span><span id='textcolor2240'><span class='ectt-0800'>"kbleds: fgconsole is %x</span></span><span id='textcolor2241'><span class='ectt-0800'>\n</span></span><span id='textcolor2242'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>, fg_console);</span>
|
|
<a id='x1-51184r55'></a><span class='ecrm-0500'>55</span><span class='ectt-0800'> </span><span id='textcolor2243'><span class='ectt-0800'>for</span></span><span class='ectt-0800'> (i = 0; i < MAX_NR_CONSOLES; i++) {</span>
|
|
<a id='x1-51186r56'></a><span class='ecrm-0500'>56</span><span class='ectt-0800'> </span><span id='textcolor2244'><span class='ectt-0800'>if</span></span><span class='ectt-0800'> (!vc_cons[i].d)</span>
|
|
<a id='x1-51188r57'></a><span class='ecrm-0500'>57</span><span class='ectt-0800'> </span><span id='textcolor2245'><span class='ectt-0800'>break</span></span><span class='ectt-0800'>;</span>
|
|
<a id='x1-51190r58'></a><span class='ecrm-0500'>58</span><span class='ectt-0800'> pr_info(</span><span id='textcolor2246'><span class='ectt-0800'>"poet_atkm: console[%i/%i] #%i, tty %lx</span></span><span id='textcolor2247'><span class='ectt-0800'>\n</span></span><span id='textcolor2248'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>, i, MAX_NR_CONSOLES,</span>
|
|
<a id='x1-51192r59'></a><span class='ecrm-0500'>59</span><span class='ectt-0800'> vc_cons[i].d->vc_num, (</span><span id='textcolor2249'><span class='ectt-0800'>unsigned</span></span><span class='ectt-0800'> </span><span id='textcolor2250'><span class='ectt-0800'>long</span></span><span class='ectt-0800'>)vc_cons[i].d->port.tty);</span>
|
|
<a id='x1-51194r60'></a><span class='ecrm-0500'>60</span><span class='ectt-0800'> }</span>
|
|
<a id='x1-51196r61'></a><span class='ecrm-0500'>61</span><span class='ectt-0800'> pr_info(</span><span id='textcolor2251'><span class='ectt-0800'>"kbleds: finished scanning consoles</span></span><span id='textcolor2252'><span class='ectt-0800'>\n</span></span><span id='textcolor2253'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>);</span>
|
|
<a id='x1-51198r62'></a><span class='ecrm-0500'>62</span>
|
|
<a id='x1-51200r63'></a><span class='ecrm-0500'>63</span><span class='ectt-0800'> my_driver = vc_cons[fg_console].d->port.tty->driver;</span>
|
|
<a id='x1-51202r64'></a><span class='ecrm-0500'>64</span><span class='ectt-0800'> pr_info(</span><span id='textcolor2254'><span class='ectt-0800'>"kbleds: tty driver magic %x</span></span><span id='textcolor2255'><span class='ectt-0800'>\n</span></span><span id='textcolor2256'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>, my_driver->magic);</span>
|
|
<a id='x1-51204r65'></a><span class='ecrm-0500'>65</span>
|
|
<a id='x1-51206r66'></a><span class='ecrm-0500'>66</span><span class='ectt-0800'> </span><span id='textcolor2257'><span class='ectt-0800'>/* Set up the LED blink timer the first time. */</span></span>
|
|
<a id='x1-51208r67'></a><span class='ecrm-0500'>67</span><span class='ectt-0800'> timer_setup(&my_timer, my_timer_func, 0);</span>
|
|
<a id='x1-51210r68'></a><span class='ecrm-0500'>68</span><span class='ectt-0800'> my_timer.expires = jiffies + BLINK_DELAY;</span>
|
|
<a id='x1-51212r69'></a><span class='ecrm-0500'>69</span><span class='ectt-0800'> add_timer(&my_timer);</span>
|
|
<a id='x1-51214r70'></a><span class='ecrm-0500'>70</span>
|
|
<a id='x1-51216r71'></a><span class='ecrm-0500'>71</span><span class='ectt-0800'> </span><span id='textcolor2258'><span class='ectt-0800'>return</span></span><span class='ectt-0800'> 0;</span>
|
|
<a id='x1-51218r72'></a><span class='ecrm-0500'>72</span><span class='ectt-0800'>}</span>
|
|
<a id='x1-51220r73'></a><span class='ecrm-0500'>73</span>
|
|
<a id='x1-51222r74'></a><span class='ecrm-0500'>74</span><span id='textcolor2259'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor2260'><span class='ectt-0800'>void</span></span><span class='ectt-0800'> __exit kbleds_cleanup(</span><span id='textcolor2261'><span class='ectt-0800'>void</span></span><span class='ectt-0800'>)</span>
|
|
<a id='x1-51224r75'></a><span class='ecrm-0500'>75</span><span class='ectt-0800'>{</span>
|
|
<a id='x1-51226r76'></a><span class='ecrm-0500'>76</span><span class='ectt-0800'> pr_info(</span><span id='textcolor2262'><span class='ectt-0800'>"kbleds: unloading...</span></span><span id='textcolor2263'><span class='ectt-0800'>\n</span></span><span id='textcolor2264'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>);</span>
|
|
<a id='x1-51228r77'></a><span class='ecrm-0500'>77</span><span class='ectt-0800'> del_timer(&my_timer);</span>
|
|
<a id='x1-51230r78'></a><span class='ecrm-0500'>78</span><span class='ectt-0800'> (my_driver->ops->ioctl)(vc_cons[fg_console].d->port.tty, KDSETLED,</span>
|
|
<a id='x1-51232r79'></a><span class='ecrm-0500'>79</span><span class='ectt-0800'> RESTORE_LEDS);</span>
|
|
<a id='x1-51234r80'></a><span class='ecrm-0500'>80</span><span class='ectt-0800'>}</span>
|
|
<a id='x1-51236r81'></a><span class='ecrm-0500'>81</span>
|
|
<a id='x1-51238r82'></a><span class='ecrm-0500'>82</span><span class='ectt-0800'>module_init(kbleds_init);</span>
|
|
<a id='x1-51240r83'></a><span class='ecrm-0500'>83</span><span class='ectt-0800'>module_exit(kbleds_cleanup);</span>
|
|
<a id='x1-51242r84'></a><span class='ecrm-0500'>84</span>
|
|
<a id='x1-51244r85'></a><span class='ecrm-0500'>85</span><span class='ectt-0800'>MODULE_LICENSE(</span><span id='textcolor2265'><span class='ectt-0800'>"GPL"</span></span><span class='ectt-0800'>);</span></pre>
|
|
<!-- l. 1549 --><p class='indent'> If none of the examples in this chapter fit your debugging needs,
|
|
there might yet be some other tricks to try. Ever wondered what
|
|
<code> <span class='ectt-1000'>CONFIG_LL_DEBUG</span>
|
|
</code> in <code> <span class='ectt-1000'>make menuconfig</span>
|
|
</code> is good for? If you activate that you get low level access to the serial port. While this
|
|
might not sound very powerful by itself, you can patch <a href='https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/tree/kernel/printk.c'>kernel/printk.c</a> or any other
|
|
essential syscall to print ASCII characters, thus making it possible to trace virtually
|
|
everything what your code does over a serial line. If you find yourself porting the
|
|
kernel to some new and former unsupported architecture, this is usually amongst the
|
|
first things that should be implemented. Logging over a netconsole might also be
|
|
worth a try.
|
|
</p><!-- l. 1556 --><p class='indent'> While you have seen lots of stuff that can be used to aid debugging here, there are
|
|
some things to be aware of. Debugging is almost always intrusive. Adding debug code
|
|
can change the situation enough to make the bug seem to dissappear. Thus you
|
|
should try to keep debug code to a minimum and make sure it does not show up in
|
|
production code.
|
|
</p><!-- l. 1560 --><p class='noindent'>
|
|
</p>
|
|
<h3 class='sectionHead' id='scheduling-tasks'><span class='titlemark'>14 </span> <a id='x1-5200014'></a>Scheduling Tasks</h3>
|
|
<!-- l. 1562 --><p class='noindent'>There are two main ways of running tasks: tasklets and work queues. Tasklets are a
|
|
quick and easy way of scheduling a single function to be run. For example, when
|
|
triggered from an interrupt, whereas work queues are more complicated but also
|
|
better suited to running multiple things in a sequence.
|
|
|
|
|
|
|
|
</p><!-- l. 1566 --><p class='noindent'>
|
|
</p>
|
|
<h4 class='subsectionHead' id='tasklets'><span class='titlemark'>14.1 </span> <a id='x1-5300014.1'></a>Tasklets</h4>
|
|
<!-- l. 1568 --><p class='noindent'>Here is an example tasklet module. The
|
|
<code> <span class='ectt-1000'>tasklet_fn</span>
|
|
</code> function runs for a few seconds and in the mean time execution of the
|
|
<code> <span class='ectt-1000'>example_tasklet_init</span>
|
|
</code> function continues to the exit point.
|
|
</p><!-- l. 1 --><p class='indent'>
|
|
</p>
|
|
<pre class='fancyvrb' id='fancyvrb66'><a id='x1-53004r1'></a><span class='ecrm-0500'>1</span><span id='textcolor2266'><span class='ectt-0800'>/*</span></span>
|
|
<a id='x1-53006r2'></a><span class='ecrm-0500'>2</span><span id='textcolor2267'><span class='ectt-0800'> * example_tasklet.c</span></span>
|
|
<a id='x1-53008r3'></a><span class='ecrm-0500'>3</span><span id='textcolor2268'><span class='ectt-0800'> */</span></span>
|
|
<a id='x1-53010r4'></a><span class='ecrm-0500'>4</span><span id='textcolor2269'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor2270'><span class='ectt-0800'><linux/delay.h></span></span>
|
|
<a id='x1-53012r5'></a><span class='ecrm-0500'>5</span><span id='textcolor2271'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor2272'><span class='ectt-0800'><linux/interrupt.h></span></span>
|
|
<a id='x1-53014r6'></a><span class='ecrm-0500'>6</span><span id='textcolor2273'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor2274'><span class='ectt-0800'><linux/kernel.h></span></span>
|
|
<a id='x1-53016r7'></a><span class='ecrm-0500'>7</span><span id='textcolor2275'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor2276'><span class='ectt-0800'><linux/module.h></span></span>
|
|
<a id='x1-53018r8'></a><span class='ecrm-0500'>8</span>
|
|
<a id='x1-53020r9'></a><span class='ecrm-0500'>9</span><span id='textcolor2277'><span class='ectt-0800'>/* Macro DECLARE_TASKLET_OLD exists for compatibiity.</span></span>
|
|
<a id='x1-53022r10'></a><span class='ecrm-0500'>10</span><span id='textcolor2278'><span class='ectt-0800'> * See https://lwn.net/Articles/830964/</span></span>
|
|
<a id='x1-53024r11'></a><span class='ecrm-0500'>11</span><span id='textcolor2279'><span class='ectt-0800'> */</span></span>
|
|
<a id='x1-53026r12'></a><span class='ecrm-0500'>12</span><span id='textcolor2280'><span class='ectt-0800'>#ifndef DECLARE_TASKLET_OLD</span></span>
|
|
<a id='x1-53028r13'></a><span class='ecrm-0500'>13</span><span id='textcolor2281'><span class='ectt-0800'>#define DECLARE_TASKLET_OLD(arg1, arg2) DECLARE_TASKLET(arg1, arg2, 0L)</span></span>
|
|
<a id='x1-53030r14'></a><span class='ecrm-0500'>14</span><span id='textcolor2282'><span class='ectt-0800'>#endif</span></span>
|
|
<a id='x1-53032r15'></a><span class='ecrm-0500'>15</span>
|
|
<a id='x1-53034r16'></a><span class='ecrm-0500'>16</span><span id='textcolor2283'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor2284'><span class='ectt-0800'>void</span></span><span class='ectt-0800'> tasklet_fn(</span><span id='textcolor2285'><span class='ectt-0800'>unsigned</span></span><span class='ectt-0800'> </span><span id='textcolor2286'><span class='ectt-0800'>long</span></span><span class='ectt-0800'> data)</span>
|
|
<a id='x1-53036r17'></a><span class='ecrm-0500'>17</span><span class='ectt-0800'>{</span>
|
|
<a id='x1-53038r18'></a><span class='ecrm-0500'>18</span><span class='ectt-0800'> pr_info(</span><span id='textcolor2287'><span class='ectt-0800'>"Example tasklet starts</span></span><span id='textcolor2288'><span class='ectt-0800'>\n</span></span><span id='textcolor2289'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>);</span>
|
|
<a id='x1-53040r19'></a><span class='ecrm-0500'>19</span><span class='ectt-0800'> mdelay(5000);</span>
|
|
<a id='x1-53042r20'></a><span class='ecrm-0500'>20</span><span class='ectt-0800'> pr_info(</span><span id='textcolor2290'><span class='ectt-0800'>"Example tasklet ends</span></span><span id='textcolor2291'><span class='ectt-0800'>\n</span></span><span id='textcolor2292'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>);</span>
|
|
<a id='x1-53044r21'></a><span class='ecrm-0500'>21</span><span class='ectt-0800'>}</span>
|
|
<a id='x1-53046r22'></a><span class='ecrm-0500'>22</span>
|
|
<a id='x1-53048r23'></a><span class='ecrm-0500'>23</span><span id='textcolor2293'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> DECLARE_TASKLET_OLD(mytask, tasklet_fn);</span>
|
|
<a id='x1-53050r24'></a><span class='ecrm-0500'>24</span>
|
|
<a id='x1-53052r25'></a><span class='ecrm-0500'>25</span><span id='textcolor2294'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor2295'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> example_tasklet_init(</span><span id='textcolor2296'><span class='ectt-0800'>void</span></span><span class='ectt-0800'>)</span>
|
|
<a id='x1-53054r26'></a><span class='ecrm-0500'>26</span><span class='ectt-0800'>{</span>
|
|
<a id='x1-53056r27'></a><span class='ecrm-0500'>27</span><span class='ectt-0800'> pr_info(</span><span id='textcolor2297'><span class='ectt-0800'>"tasklet example init</span></span><span id='textcolor2298'><span class='ectt-0800'>\n</span></span><span id='textcolor2299'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>);</span>
|
|
<a id='x1-53058r28'></a><span class='ecrm-0500'>28</span><span class='ectt-0800'> tasklet_schedule(&mytask);</span>
|
|
<a id='x1-53060r29'></a><span class='ecrm-0500'>29</span><span class='ectt-0800'> mdelay(200);</span>
|
|
<a id='x1-53062r30'></a><span class='ecrm-0500'>30</span><span class='ectt-0800'> pr_info(</span><span id='textcolor2300'><span class='ectt-0800'>"Example tasklet init continues...</span></span><span id='textcolor2301'><span class='ectt-0800'>\n</span></span><span id='textcolor2302'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>);</span>
|
|
<a id='x1-53064r31'></a><span class='ecrm-0500'>31</span><span class='ectt-0800'> </span><span id='textcolor2303'><span class='ectt-0800'>return</span></span><span class='ectt-0800'> 0;</span>
|
|
<a id='x1-53066r32'></a><span class='ecrm-0500'>32</span><span class='ectt-0800'>}</span>
|
|
<a id='x1-53068r33'></a><span class='ecrm-0500'>33</span>
|
|
<a id='x1-53070r34'></a><span class='ecrm-0500'>34</span><span id='textcolor2304'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor2305'><span class='ectt-0800'>void</span></span><span class='ectt-0800'> example_tasklet_exit(</span><span id='textcolor2306'><span class='ectt-0800'>void</span></span><span class='ectt-0800'>)</span>
|
|
<a id='x1-53072r35'></a><span class='ecrm-0500'>35</span><span class='ectt-0800'>{</span>
|
|
<a id='x1-53074r36'></a><span class='ecrm-0500'>36</span><span class='ectt-0800'> pr_info(</span><span id='textcolor2307'><span class='ectt-0800'>"tasklet example exit</span></span><span id='textcolor2308'><span class='ectt-0800'>\n</span></span><span id='textcolor2309'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>);</span>
|
|
<a id='x1-53076r37'></a><span class='ecrm-0500'>37</span><span class='ectt-0800'> tasklet_kill(&mytask);</span>
|
|
<a id='x1-53078r38'></a><span class='ecrm-0500'>38</span><span class='ectt-0800'>}</span>
|
|
<a id='x1-53080r39'></a><span class='ecrm-0500'>39</span>
|
|
<a id='x1-53082r40'></a><span class='ecrm-0500'>40</span><span class='ectt-0800'>module_init(example_tasklet_init);</span>
|
|
<a id='x1-53084r41'></a><span class='ecrm-0500'>41</span><span class='ectt-0800'>module_exit(example_tasklet_exit);</span>
|
|
<a id='x1-53086r42'></a><span class='ecrm-0500'>42</span>
|
|
<a id='x1-53088r43'></a><span class='ecrm-0500'>43</span><span class='ectt-0800'>MODULE_DESCRIPTION(</span><span id='textcolor2310'><span class='ectt-0800'>"Tasklet example"</span></span><span class='ectt-0800'>);</span>
|
|
<a id='x1-53090r44'></a><span class='ecrm-0500'>44</span><span class='ectt-0800'>MODULE_LICENSE(</span><span id='textcolor2311'><span class='ectt-0800'>"GPL"</span></span><span class='ectt-0800'>);</span></pre>
|
|
<!-- l. 1573 --><p class='indent'> So with this example loaded <code> <span class='ectt-1000'>dmesg</span>
|
|
</code> should show:
|
|
|
|
|
|
|
|
</p>
|
|
<pre class='verbatim' id='verbatim-16'>
|
|
tasklet example init
|
|
Example tasklet starts
|
|
Example tasklet init continues...
|
|
Example tasklet ends
|
|
</pre>
|
|
<!-- l. 1580 --><p class='nopar'>Although tasklet is easy to use, it comes with several defators, and developers are
|
|
discussing about getting rid of tasklet in linux kernel. The tasklet callback
|
|
runs in atomic context, inside a software interrupt, meaning that it cannot
|
|
sleep or access user-space data, so not all work can be done in a tasklet
|
|
handler. Also, the kernel only allows one instance of any given tasklet to be
|
|
running at any given time; multiple different tasklet callbacks can run in
|
|
parallel.
|
|
</p><!-- l. 1585 --><p class='indent'> In recent kernels, tasklets can be replaced by workqueues, timers, or threaded
|
|
interrupts.<span class='footnote-mark'><a href='#fn1x0' id='fn1x0-bk'><sup class='textsuperscript'>1</sup></a></span><a id='x1-53092f1'></a>
|
|
While the removal of tasklets remains a longer-term goal, the current kernel contains more
|
|
than a hundred uses of tasklets. Now developers are proceeding with the API changes and
|
|
the macro <code> <span class='ectt-1000'>DECLARE_TASKLET_OLD</span>
|
|
</code> exists for compatibiity. For further information, see <a class='url' href='https://lwn.net/Articles/830964/'><span class='ectt-1000'>https://lwn.net/Articles/830964/</span></a>.
|
|
</p><!-- l. 1591 --><p class='noindent'>
|
|
</p>
|
|
<h4 class='subsectionHead' id='work-queues'><span class='titlemark'>14.2 </span> <a id='x1-5400014.2'></a>Work queues</h4>
|
|
<!-- l. 1593 --><p class='noindent'>To add a task to the scheduler we can use a workqueue. The kernel then uses the
|
|
Completely Fair Scheduler (CFS) to execute work within the queue.
|
|
</p><!-- l. 1 --><p class='indent'>
|
|
</p>
|
|
<pre class='fancyvrb' id='fancyvrb67'><a id='x1-54002r1'></a><span class='ecrm-0500'>1</span><span id='textcolor2312'><span class='ectt-0800'>/*</span></span>
|
|
<a id='x1-54004r2'></a><span class='ecrm-0500'>2</span><span id='textcolor2313'><span class='ectt-0800'> * sched.c</span></span>
|
|
<a id='x1-54006r3'></a><span class='ecrm-0500'>3</span><span id='textcolor2314'><span class='ectt-0800'> */</span></span>
|
|
<a id='x1-54008r4'></a><span class='ecrm-0500'>4</span><span id='textcolor2315'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor2316'><span class='ectt-0800'><linux/init.h></span></span>
|
|
<a id='x1-54010r5'></a><span class='ecrm-0500'>5</span><span id='textcolor2317'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor2318'><span class='ectt-0800'><linux/module.h></span></span>
|
|
<a id='x1-54012r6'></a><span class='ecrm-0500'>6</span><span id='textcolor2319'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor2320'><span class='ectt-0800'><linux/workqueue.h></span></span>
|
|
<a id='x1-54014r7'></a><span class='ecrm-0500'>7</span>
|
|
<a id='x1-54016r8'></a><span class='ecrm-0500'>8</span><span id='textcolor2321'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor2322'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> workqueue_struct *queue = NULL;</span>
|
|
<a id='x1-54018r9'></a><span class='ecrm-0500'>9</span><span id='textcolor2323'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor2324'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> work_struct work;</span>
|
|
<a id='x1-54020r10'></a><span class='ecrm-0500'>10</span>
|
|
<a id='x1-54022r11'></a><span class='ecrm-0500'>11</span><span id='textcolor2325'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor2326'><span class='ectt-0800'>void</span></span><span class='ectt-0800'> work_handler(</span><span id='textcolor2327'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> work_struct *data)</span>
|
|
<a id='x1-54024r12'></a><span class='ecrm-0500'>12</span><span class='ectt-0800'>{</span>
|
|
<a id='x1-54026r13'></a><span class='ecrm-0500'>13</span><span class='ectt-0800'> pr_info(</span><span id='textcolor2328'><span class='ectt-0800'>"work handler function.</span></span><span id='textcolor2329'><span class='ectt-0800'>\n</span></span><span id='textcolor2330'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>);</span>
|
|
<a id='x1-54028r14'></a><span class='ecrm-0500'>14</span><span class='ectt-0800'>}</span>
|
|
<a id='x1-54030r15'></a><span class='ecrm-0500'>15</span>
|
|
<a id='x1-54032r16'></a><span class='ecrm-0500'>16</span><span id='textcolor2331'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor2332'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> __init sched_init(</span><span id='textcolor2333'><span class='ectt-0800'>void</span></span><span class='ectt-0800'>)</span>
|
|
<a id='x1-54034r17'></a><span class='ecrm-0500'>17</span><span class='ectt-0800'>{</span>
|
|
<a id='x1-54036r18'></a><span class='ecrm-0500'>18</span><span class='ectt-0800'> queue = alloc_workqueue(</span><span id='textcolor2334'><span class='ectt-0800'>"HELLOWORLD"</span></span><span class='ectt-0800'>, WQ_UNBOUND, 1);</span>
|
|
<a id='x1-54038r19'></a><span class='ecrm-0500'>19</span><span class='ectt-0800'> INIT_WORK(&work, work_handler);</span>
|
|
<a id='x1-54040r20'></a><span class='ecrm-0500'>20</span><span class='ectt-0800'> schedule_work(&work);</span>
|
|
<a id='x1-54042r21'></a><span class='ecrm-0500'>21</span><span class='ectt-0800'> </span><span id='textcolor2335'><span class='ectt-0800'>return</span></span><span class='ectt-0800'> 0;</span>
|
|
<a id='x1-54044r22'></a><span class='ecrm-0500'>22</span><span class='ectt-0800'>}</span>
|
|
<a id='x1-54046r23'></a><span class='ecrm-0500'>23</span>
|
|
<a id='x1-54048r24'></a><span class='ecrm-0500'>24</span><span id='textcolor2336'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor2337'><span class='ectt-0800'>void</span></span><span class='ectt-0800'> __exit sched_exit(</span><span id='textcolor2338'><span class='ectt-0800'>void</span></span><span class='ectt-0800'>)</span>
|
|
<a id='x1-54050r25'></a><span class='ecrm-0500'>25</span><span class='ectt-0800'>{</span>
|
|
<a id='x1-54052r26'></a><span class='ecrm-0500'>26</span><span class='ectt-0800'> destroy_workqueue(queue);</span>
|
|
<a id='x1-54054r27'></a><span class='ecrm-0500'>27</span><span class='ectt-0800'>}</span>
|
|
<a id='x1-54056r28'></a><span class='ecrm-0500'>28</span>
|
|
<a id='x1-54058r29'></a><span class='ecrm-0500'>29</span><span class='ectt-0800'>module_init(sched_init);</span>
|
|
<a id='x1-54060r30'></a><span class='ecrm-0500'>30</span><span class='ectt-0800'>module_exit(sched_exit);</span>
|
|
<a id='x1-54062r31'></a><span class='ecrm-0500'>31</span>
|
|
<a id='x1-54064r32'></a><span class='ecrm-0500'>32</span><span class='ectt-0800'>MODULE_LICENSE(</span><span id='textcolor2339'><span class='ectt-0800'>"GPL"</span></span><span class='ectt-0800'>);</span>
|
|
<a id='x1-54066r33'></a><span class='ecrm-0500'>33</span><span class='ectt-0800'>MODULE_DESCRIPTION(</span><span id='textcolor2340'><span class='ectt-0800'>"Workqueue example"</span></span><span class='ectt-0800'>);</span></pre>
|
|
<!-- l. 1598 --><p class='noindent'>
|
|
</p>
|
|
<h3 class='sectionHead' id='interrupt-handlers'><span class='titlemark'>15 </span> <a id='x1-5500015'></a>Interrupt Handlers</h3>
|
|
<!-- l. 1600 --><p class='noindent'>
|
|
</p>
|
|
|
|
|
|
|
|
<h4 class='subsectionHead' id='interrupt-handlers1'><span class='titlemark'>15.1 </span> <a id='x1-5600015.1'></a>Interrupt Handlers</h4>
|
|
<!-- l. 1602 --><p class='noindent'>Except for the last chapter, everything we did in the kernel so far we have done as a
|
|
response to a process asking for it, either by dealing with a special file, sending an
|
|
<code> <span class='ectt-1000'>ioctl()</span>
|
|
</code>, or issuing a system call. But the job of the kernel is not just to respond to process
|
|
requests. Another job, which is every bit as important, is to speak to the hardware
|
|
connected to the machine.
|
|
</p><!-- l. 1606 --><p class='indent'> There are two types of interaction between the CPU and the rest of the
|
|
computer’s hardware. The first type is when the CPU gives orders to the hardware,
|
|
the order is when the hardware needs to tell the CPU something. The second, called
|
|
interrupts, is much harder to implement because it has to be dealt with when
|
|
convenient for the hardware, not the CPU. Hardware devices typically have a very
|
|
small amount of RAM, and if you do not read their information when available, it is
|
|
lost.
|
|
</p><!-- l. 1611 --><p class='indent'> Under Linux, hardware interrupts are called IRQ’s (Interrupt ReQuests). There
|
|
are two types of IRQ’s, short and long. A short IRQ is one which is expected to take
|
|
a very short period of time, during which the rest of the machine will be blocked and
|
|
no other interrupts will be handled. A long IRQ is one which can take longer, and
|
|
during which other interrupts may occur (but not interrupts from the same
|
|
device). If at all possible, it is better to declare an interrupt handler to be
|
|
long.
|
|
</p><!-- l. 1617 --><p class='indent'> When the CPU receives an interrupt, it stops whatever it is doing (unless it is
|
|
processing a more important interrupt, in which case it will deal with this one only
|
|
when the more important one is done), saves certain parameters on the stack and
|
|
calls the interrupt handler. This means that certain things are not allowed in the
|
|
interrupt handler itself, because the system is in an unknown state. Linux kernel
|
|
solves the problem by splitting interrupt handling into two parts. The first part
|
|
executes right away and masks the interrupt line. Hardware interrupts must be
|
|
handled quickly, and that is why we need the second part to handle the
|
|
heavy work deferred from an interrupt handler. Historically, BH (Linux
|
|
naming for <span class='ecti-1000'>Bottom Halves</span>) statistically book-keeps the deferred functions.
|
|
<span class='ecbx-1000'>Softirq </span>and its higher level abstraction, <span class='ecbx-1000'>Tasklet</span>, replace BH since Linux
|
|
2.3.
|
|
</p><!-- l. 1627 --><p class='indent'> The way to implement this is to call
|
|
<code> <span class='ectt-1000'>request_irq()</span>
|
|
</code> to get your interrupt handler called when the relevant IRQ is received.
|
|
</p><!-- l. 1629 --><p class='indent'> In practice IRQ handling can be a bit more complex. Hardware is often
|
|
designed in a way that chains two interrupt controllers, so that all the IRQs
|
|
from interrupt controller B are cascaded to a certain IRQ from interrupt
|
|
controller A. Of course, that requires that the kernel finds out which IRQ it
|
|
really was afterwards and that adds overhead. Other architectures offer some
|
|
special, very low overhead, so called "fast IRQ" or FIQs. To take advantage of
|
|
them requires handlers to be written in assembler, so they do not really
|
|
fit into the kernel. They can be made to work similar to the others, but
|
|
after that procedure, they are no longer any faster than "common" IRQs.
|
|
SMP enabled kernels running on systems with more than one processor
|
|
|
|
|
|
|
|
need to solve another truckload of problems. It is not enough to know if a
|
|
certain IRQs has happened, it’s also important to know what CPU(s) it was
|
|
for. People still interested in more details, might want to refer to "APIC"
|
|
now.
|
|
</p><!-- l. 1638 --><p class='indent'> This function receives the IRQ number, the name of the function,
|
|
flags, a name for <span class='obeylines-h'><span class='verb'><span class='ectt-1000'>/proc/interrupts</span></span></span> and a parameter to be passed to the
|
|
interrupt handler. Usually there is a certain number of IRQs available.
|
|
How many IRQs there are is hardware-dependent. The flags can include
|
|
<code> <span class='ectt-1000'>SA_SHIRQ</span>
|
|
</code> to indicate you are willing to share the IRQ with other interrupt handlers
|
|
(usually because a number of hardware devices sit on the same IRQ) and
|
|
<code> <span class='ectt-1000'>SA_INTERRUPT</span>
|
|
</code> to indicate this is a fast interrupt. This function will only succeed if there is not
|
|
already a handler on this IRQ, or if you are both willing to share.
|
|
</p><!-- l. 1644 --><p class='noindent'>
|
|
</p>
|
|
<h4 class='subsectionHead' id='detecting-button-presses'><span class='titlemark'>15.2 </span> <a id='x1-5700015.2'></a>Detecting button presses</h4>
|
|
<!-- l. 1646 --><p class='noindent'>Many popular single board computers, such as Raspberry Pi or Beagleboards, have a
|
|
bunch of GPIO pins. Attaching buttons to those and then having a button press do
|
|
something is a classic case in which you might need to use interrupts, so that instead
|
|
of having the CPU waste time and battery power polling for a change in input state,
|
|
it is better for the input to trigger the CPU to then run a particular handling
|
|
function.
|
|
</p><!-- l. 1650 --><p class='indent'> Here is an example where buttons are connected to GPIO numbers 17 and 18 and
|
|
an LED is connected to GPIO 4. You can change those numbers to whatever is
|
|
appropriate for your board.
|
|
</p><!-- l. 1 --><p class='indent'>
|
|
</p>
|
|
<pre class='fancyvrb' id='fancyvrb68'><a id='x1-57002r1'></a><span class='ecrm-0500'>1</span><span id='textcolor2341'><span class='ectt-0800'>/*</span></span>
|
|
<a id='x1-57004r2'></a><span class='ecrm-0500'>2</span><span id='textcolor2342'><span class='ectt-0800'> * intrpt.c - Handling GPIO with interrupts</span></span>
|
|
<a id='x1-57006r3'></a><span class='ecrm-0500'>3</span><span id='textcolor2343'><span class='ectt-0800'> *</span></span>
|
|
<a id='x1-57008r4'></a><span class='ecrm-0500'>4</span><span id='textcolor2344'><span class='ectt-0800'> * Based upon the RPi example by Stefan Wendler (devnull@kaltpost.de)</span></span>
|
|
<a id='x1-57010r5'></a><span class='ecrm-0500'>5</span><span id='textcolor2345'><span class='ectt-0800'> * from:</span></span>
|
|
<a id='x1-57012r6'></a><span class='ecrm-0500'>6</span><span id='textcolor2346'><span class='ectt-0800'> * https://github.com/wendlers/rpi-kmod-samples</span></span>
|
|
<a id='x1-57014r7'></a><span class='ecrm-0500'>7</span><span id='textcolor2347'><span class='ectt-0800'> *</span></span>
|
|
<a id='x1-57016r8'></a><span class='ecrm-0500'>8</span><span id='textcolor2348'><span class='ectt-0800'> * Press one button to turn on a LED and another to turn it off.</span></span>
|
|
<a id='x1-57018r9'></a><span class='ecrm-0500'>9</span><span id='textcolor2349'><span class='ectt-0800'> */</span></span>
|
|
<a id='x1-57020r10'></a><span class='ecrm-0500'>10</span>
|
|
<a id='x1-57022r11'></a><span class='ecrm-0500'>11</span><span id='textcolor2350'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor2351'><span class='ectt-0800'><linux/gpio.h></span></span>
|
|
<a id='x1-57024r12'></a><span class='ecrm-0500'>12</span><span id='textcolor2352'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor2353'><span class='ectt-0800'><linux/interrupt.h></span></span>
|
|
<a id='x1-57026r13'></a><span class='ecrm-0500'>13</span><span id='textcolor2354'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor2355'><span class='ectt-0800'><linux/kernel.h></span></span>
|
|
<a id='x1-57028r14'></a><span class='ecrm-0500'>14</span><span id='textcolor2356'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor2357'><span class='ectt-0800'><linux/module.h></span></span>
|
|
<a id='x1-57030r15'></a><span class='ecrm-0500'>15</span>
|
|
<a id='x1-57032r16'></a><span class='ecrm-0500'>16</span><span id='textcolor2358'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor2359'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> button_irqs[] = { -1, -1 };</span>
|
|
<a id='x1-57034r17'></a><span class='ecrm-0500'>17</span>
|
|
<a id='x1-57036r18'></a><span class='ecrm-0500'>18</span><span id='textcolor2360'><span class='ectt-0800'>/* Define GPIOs for LEDs.</span></span>
|
|
<a id='x1-57038r19'></a><span class='ecrm-0500'>19</span><span id='textcolor2361'><span class='ectt-0800'> * TODO: Change the numbers for the GPIO on your board.</span></span>
|
|
<a id='x1-57040r20'></a><span class='ecrm-0500'>20</span><span id='textcolor2362'><span class='ectt-0800'> */</span></span>
|
|
<a id='x1-57042r21'></a><span class='ecrm-0500'>21</span><span id='textcolor2363'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor2364'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> gpio leds[] = { { 4, GPIOF_OUT_INIT_LOW, </span><span id='textcolor2365'><span class='ectt-0800'>"LED 1"</span></span><span class='ectt-0800'> } };</span>
|
|
<a id='x1-57044r22'></a><span class='ecrm-0500'>22</span>
|
|
<a id='x1-57046r23'></a><span class='ecrm-0500'>23</span><span id='textcolor2366'><span class='ectt-0800'>/* Define GPIOs for BUTTONS</span></span>
|
|
<a id='x1-57048r24'></a><span class='ecrm-0500'>24</span><span id='textcolor2367'><span class='ectt-0800'> * TODO: Change the numbers for the GPIO on your board.</span></span>
|
|
<a id='x1-57050r25'></a><span class='ecrm-0500'>25</span><span id='textcolor2368'><span class='ectt-0800'> */</span></span>
|
|
<a id='x1-57052r26'></a><span class='ecrm-0500'>26</span><span id='textcolor2369'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor2370'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> gpio buttons[] = { { 17, GPIOF_IN, </span><span id='textcolor2371'><span class='ectt-0800'>"LED 1 ON BUTTON"</span></span><span class='ectt-0800'> },</span>
|
|
<a id='x1-57054r27'></a><span class='ecrm-0500'>27</span><span class='ectt-0800'> { 18, GPIOF_IN, </span><span id='textcolor2372'><span class='ectt-0800'>"LED 1 OFF BUTTON"</span></span><span class='ectt-0800'> } };</span>
|
|
<a id='x1-57056r28'></a><span class='ecrm-0500'>28</span>
|
|
<a id='x1-57058r29'></a><span class='ecrm-0500'>29</span><span id='textcolor2373'><span class='ectt-0800'>/* interrupt function triggered when a button is pressed. */</span></span>
|
|
<a id='x1-57060r30'></a><span class='ecrm-0500'>30</span><span id='textcolor2374'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> irqreturn_t button_isr(</span><span id='textcolor2375'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> irq, </span><span id='textcolor2376'><span class='ectt-0800'>void</span></span><span class='ectt-0800'> *data)</span>
|
|
<a id='x1-57062r31'></a><span class='ecrm-0500'>31</span><span class='ectt-0800'>{</span>
|
|
<a id='x1-57064r32'></a><span class='ecrm-0500'>32</span><span class='ectt-0800'> </span><span id='textcolor2377'><span class='ectt-0800'>/* first button */</span></span>
|
|
<a id='x1-57066r33'></a><span class='ecrm-0500'>33</span><span class='ectt-0800'> </span><span id='textcolor2378'><span class='ectt-0800'>if</span></span><span class='ectt-0800'> (irq == button_irqs[0] && !gpio_get_value(leds[0].gpio))</span>
|
|
<a id='x1-57068r34'></a><span class='ecrm-0500'>34</span><span class='ectt-0800'> gpio_set_value(leds[0].gpio, 1);</span>
|
|
<a id='x1-57070r35'></a><span class='ecrm-0500'>35</span><span class='ectt-0800'> </span><span id='textcolor2379'><span class='ectt-0800'>/* second button */</span></span>
|
|
<a id='x1-57072r36'></a><span class='ecrm-0500'>36</span><span class='ectt-0800'> </span><span id='textcolor2380'><span class='ectt-0800'>else</span></span><span class='ectt-0800'> </span><span id='textcolor2381'><span class='ectt-0800'>if</span></span><span class='ectt-0800'> (irq == button_irqs[1] && gpio_get_value(leds[0].gpio))</span>
|
|
<a id='x1-57074r37'></a><span class='ecrm-0500'>37</span><span class='ectt-0800'> gpio_set_value(leds[0].gpio, 0);</span>
|
|
<a id='x1-57076r38'></a><span class='ecrm-0500'>38</span>
|
|
<a id='x1-57078r39'></a><span class='ecrm-0500'>39</span><span class='ectt-0800'> </span><span id='textcolor2382'><span class='ectt-0800'>return</span></span><span class='ectt-0800'> IRQ_HANDLED;</span>
|
|
<a id='x1-57080r40'></a><span class='ecrm-0500'>40</span><span class='ectt-0800'>}</span>
|
|
<a id='x1-57082r41'></a><span class='ecrm-0500'>41</span>
|
|
<a id='x1-57084r42'></a><span class='ecrm-0500'>42</span><span id='textcolor2383'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor2384'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> __init intrpt_init(</span><span id='textcolor2385'><span class='ectt-0800'>void</span></span><span class='ectt-0800'>)</span>
|
|
<a id='x1-57086r43'></a><span class='ecrm-0500'>43</span><span class='ectt-0800'>{</span>
|
|
<a id='x1-57088r44'></a><span class='ecrm-0500'>44</span><span class='ectt-0800'> </span><span id='textcolor2386'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> ret = 0;</span>
|
|
<a id='x1-57090r45'></a><span class='ecrm-0500'>45</span>
|
|
<a id='x1-57092r46'></a><span class='ecrm-0500'>46</span><span class='ectt-0800'> pr_info(</span><span id='textcolor2387'><span class='ectt-0800'>"%s</span></span><span id='textcolor2388'><span class='ectt-0800'>\n</span></span><span id='textcolor2389'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>, __func__);</span>
|
|
<a id='x1-57094r47'></a><span class='ecrm-0500'>47</span>
|
|
<a id='x1-57096r48'></a><span class='ecrm-0500'>48</span><span class='ectt-0800'> </span><span id='textcolor2390'><span class='ectt-0800'>/* register LED gpios */</span></span>
|
|
<a id='x1-57098r49'></a><span class='ecrm-0500'>49</span><span class='ectt-0800'> ret = gpio_request_array(leds, ARRAY_SIZE(leds));</span>
|
|
<a id='x1-57100r50'></a><span class='ecrm-0500'>50</span>
|
|
<a id='x1-57102r51'></a><span class='ecrm-0500'>51</span><span class='ectt-0800'> </span><span id='textcolor2391'><span class='ectt-0800'>if</span></span><span class='ectt-0800'> (ret) {</span>
|
|
<a id='x1-57104r52'></a><span class='ecrm-0500'>52</span><span class='ectt-0800'> pr_err(</span><span id='textcolor2392'><span class='ectt-0800'>"Unable to request GPIOs for LEDs: %d</span></span><span id='textcolor2393'><span class='ectt-0800'>\n</span></span><span id='textcolor2394'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>, ret);</span>
|
|
<a id='x1-57106r53'></a><span class='ecrm-0500'>53</span><span class='ectt-0800'> </span><span id='textcolor2395'><span class='ectt-0800'>return</span></span><span class='ectt-0800'> ret;</span>
|
|
<a id='x1-57108r54'></a><span class='ecrm-0500'>54</span><span class='ectt-0800'> }</span>
|
|
<a id='x1-57110r55'></a><span class='ecrm-0500'>55</span>
|
|
<a id='x1-57112r56'></a><span class='ecrm-0500'>56</span><span class='ectt-0800'> </span><span id='textcolor2396'><span class='ectt-0800'>/* register BUTTON gpios */</span></span>
|
|
<a id='x1-57114r57'></a><span class='ecrm-0500'>57</span><span class='ectt-0800'> ret = gpio_request_array(buttons, ARRAY_SIZE(buttons));</span>
|
|
<a id='x1-57116r58'></a><span class='ecrm-0500'>58</span>
|
|
<a id='x1-57118r59'></a><span class='ecrm-0500'>59</span><span class='ectt-0800'> </span><span id='textcolor2397'><span class='ectt-0800'>if</span></span><span class='ectt-0800'> (ret) {</span>
|
|
<a id='x1-57120r60'></a><span class='ecrm-0500'>60</span><span class='ectt-0800'> pr_err(</span><span id='textcolor2398'><span class='ectt-0800'>"Unable to request GPIOs for BUTTONs: %d</span></span><span id='textcolor2399'><span class='ectt-0800'>\n</span></span><span id='textcolor2400'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>, ret);</span>
|
|
<a id='x1-57122r61'></a><span class='ecrm-0500'>61</span><span class='ectt-0800'> </span><span id='textcolor2401'><span class='ectt-0800'>goto</span></span><span class='ectt-0800'> fail1;</span>
|
|
<a id='x1-57124r62'></a><span class='ecrm-0500'>62</span><span class='ectt-0800'> }</span>
|
|
<a id='x1-57126r63'></a><span class='ecrm-0500'>63</span>
|
|
<a id='x1-57128r64'></a><span class='ecrm-0500'>64</span><span class='ectt-0800'> pr_info(</span><span id='textcolor2402'><span class='ectt-0800'>"Current button1 value: %d</span></span><span id='textcolor2403'><span class='ectt-0800'>\n</span></span><span id='textcolor2404'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>, gpio_get_value(buttons[0].gpio));</span>
|
|
<a id='x1-57130r65'></a><span class='ecrm-0500'>65</span>
|
|
<a id='x1-57132r66'></a><span class='ecrm-0500'>66</span><span class='ectt-0800'> ret = gpio_to_irq(buttons[0].gpio);</span>
|
|
<a id='x1-57134r67'></a><span class='ecrm-0500'>67</span>
|
|
<a id='x1-57136r68'></a><span class='ecrm-0500'>68</span><span class='ectt-0800'> </span><span id='textcolor2405'><span class='ectt-0800'>if</span></span><span class='ectt-0800'> (ret < 0) {</span>
|
|
<a id='x1-57138r69'></a><span class='ecrm-0500'>69</span><span class='ectt-0800'> pr_err(</span><span id='textcolor2406'><span class='ectt-0800'>"Unable to request IRQ: %d</span></span><span id='textcolor2407'><span class='ectt-0800'>\n</span></span><span id='textcolor2408'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>, ret);</span>
|
|
<a id='x1-57140r70'></a><span class='ecrm-0500'>70</span><span class='ectt-0800'> </span><span id='textcolor2409'><span class='ectt-0800'>goto</span></span><span class='ectt-0800'> fail2;</span>
|
|
<a id='x1-57142r71'></a><span class='ecrm-0500'>71</span><span class='ectt-0800'> }</span>
|
|
<a id='x1-57144r72'></a><span class='ecrm-0500'>72</span>
|
|
<a id='x1-57146r73'></a><span class='ecrm-0500'>73</span><span class='ectt-0800'> button_irqs[0] = ret;</span>
|
|
<a id='x1-57148r74'></a><span class='ecrm-0500'>74</span>
|
|
<a id='x1-57150r75'></a><span class='ecrm-0500'>75</span><span class='ectt-0800'> pr_info(</span><span id='textcolor2410'><span class='ectt-0800'>"Successfully requested BUTTON1 IRQ # %d</span></span><span id='textcolor2411'><span class='ectt-0800'>\n</span></span><span id='textcolor2412'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>, button_irqs[0]);</span>
|
|
<a id='x1-57152r76'></a><span class='ecrm-0500'>76</span>
|
|
<a id='x1-57154r77'></a><span class='ecrm-0500'>77</span><span class='ectt-0800'> ret = request_irq(button_irqs[0], button_isr,</span>
|
|
<a id='x1-57156r78'></a><span class='ecrm-0500'>78</span><span class='ectt-0800'> IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,</span>
|
|
<a id='x1-57158r79'></a><span class='ecrm-0500'>79</span><span class='ectt-0800'> </span><span id='textcolor2413'><span class='ectt-0800'>"gpiomod#button1"</span></span><span class='ectt-0800'>, NULL);</span>
|
|
<a id='x1-57160r80'></a><span class='ecrm-0500'>80</span>
|
|
<a id='x1-57162r81'></a><span class='ecrm-0500'>81</span><span class='ectt-0800'> </span><span id='textcolor2414'><span class='ectt-0800'>if</span></span><span class='ectt-0800'> (ret) {</span>
|
|
<a id='x1-57164r82'></a><span class='ecrm-0500'>82</span><span class='ectt-0800'> pr_err(</span><span id='textcolor2415'><span class='ectt-0800'>"Unable to request IRQ: %d</span></span><span id='textcolor2416'><span class='ectt-0800'>\n</span></span><span id='textcolor2417'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>, ret);</span>
|
|
<a id='x1-57166r83'></a><span class='ecrm-0500'>83</span><span class='ectt-0800'> </span><span id='textcolor2418'><span class='ectt-0800'>goto</span></span><span class='ectt-0800'> fail2;</span>
|
|
<a id='x1-57168r84'></a><span class='ecrm-0500'>84</span><span class='ectt-0800'> }</span>
|
|
<a id='x1-57170r85'></a><span class='ecrm-0500'>85</span>
|
|
<a id='x1-57172r86'></a><span class='ecrm-0500'>86</span><span class='ectt-0800'> ret = gpio_to_irq(buttons[1].gpio);</span>
|
|
<a id='x1-57174r87'></a><span class='ecrm-0500'>87</span>
|
|
<a id='x1-57176r88'></a><span class='ecrm-0500'>88</span><span class='ectt-0800'> </span><span id='textcolor2419'><span class='ectt-0800'>if</span></span><span class='ectt-0800'> (ret < 0) {</span>
|
|
<a id='x1-57178r89'></a><span class='ecrm-0500'>89</span><span class='ectt-0800'> pr_err(</span><span id='textcolor2420'><span class='ectt-0800'>"Unable to request IRQ: %d</span></span><span id='textcolor2421'><span class='ectt-0800'>\n</span></span><span id='textcolor2422'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>, ret);</span>
|
|
<a id='x1-57180r90'></a><span class='ecrm-0500'>90</span><span class='ectt-0800'> </span><span id='textcolor2423'><span class='ectt-0800'>goto</span></span><span class='ectt-0800'> fail2;</span>
|
|
<a id='x1-57182r91'></a><span class='ecrm-0500'>91</span><span class='ectt-0800'> }</span>
|
|
<a id='x1-57184r92'></a><span class='ecrm-0500'>92</span>
|
|
<a id='x1-57186r93'></a><span class='ecrm-0500'>93</span><span class='ectt-0800'> button_irqs[1] = ret;</span>
|
|
<a id='x1-57188r94'></a><span class='ecrm-0500'>94</span>
|
|
<a id='x1-57190r95'></a><span class='ecrm-0500'>95</span><span class='ectt-0800'> pr_info(</span><span id='textcolor2424'><span class='ectt-0800'>"Successfully requested BUTTON2 IRQ # %d</span></span><span id='textcolor2425'><span class='ectt-0800'>\n</span></span><span id='textcolor2426'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>, button_irqs[1]);</span>
|
|
<a id='x1-57192r96'></a><span class='ecrm-0500'>96</span>
|
|
<a id='x1-57194r97'></a><span class='ecrm-0500'>97</span><span class='ectt-0800'> ret = request_irq(button_irqs[1], button_isr,</span>
|
|
<a id='x1-57196r98'></a><span class='ecrm-0500'>98</span><span class='ectt-0800'> IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,</span>
|
|
<a id='x1-57198r99'></a><span class='ecrm-0500'>99</span><span class='ectt-0800'> </span><span id='textcolor2427'><span class='ectt-0800'>"gpiomod#button2"</span></span><span class='ectt-0800'>, NULL);</span>
|
|
<a id='x1-57200r100'></a><span class='ecrm-0500'>100</span>
|
|
<a id='x1-57202r101'></a><span class='ecrm-0500'>101</span><span class='ectt-0800'> </span><span id='textcolor2428'><span class='ectt-0800'>if</span></span><span class='ectt-0800'> (ret) {</span>
|
|
<a id='x1-57204r102'></a><span class='ecrm-0500'>102</span><span class='ectt-0800'> pr_err(</span><span id='textcolor2429'><span class='ectt-0800'>"Unable to request IRQ: %d</span></span><span id='textcolor2430'><span class='ectt-0800'>\n</span></span><span id='textcolor2431'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>, ret);</span>
|
|
<a id='x1-57206r103'></a><span class='ecrm-0500'>103</span><span class='ectt-0800'> </span><span id='textcolor2432'><span class='ectt-0800'>goto</span></span><span class='ectt-0800'> fail3;</span>
|
|
<a id='x1-57208r104'></a><span class='ecrm-0500'>104</span><span class='ectt-0800'> }</span>
|
|
<a id='x1-57210r105'></a><span class='ecrm-0500'>105</span>
|
|
<a id='x1-57212r106'></a><span class='ecrm-0500'>106</span><span class='ectt-0800'> </span><span id='textcolor2433'><span class='ectt-0800'>return</span></span><span class='ectt-0800'> 0;</span>
|
|
<a id='x1-57214r107'></a><span class='ecrm-0500'>107</span>
|
|
<a id='x1-57216r108'></a><span class='ecrm-0500'>108</span><span id='textcolor2434'><span class='ectt-0800'>/* cleanup what has been setup so far */</span></span>
|
|
<a id='x1-57218r109'></a><span class='ecrm-0500'>109</span><span class='ectt-0800'>fail3:</span>
|
|
<a id='x1-57220r110'></a><span class='ecrm-0500'>110</span><span class='ectt-0800'> free_irq(button_irqs[0], NULL);</span>
|
|
<a id='x1-57222r111'></a><span class='ecrm-0500'>111</span>
|
|
<a id='x1-57224r112'></a><span class='ecrm-0500'>112</span><span class='ectt-0800'>fail2:</span>
|
|
<a id='x1-57226r113'></a><span class='ecrm-0500'>113</span><span class='ectt-0800'> gpio_free_array(buttons, ARRAY_SIZE(leds));</span>
|
|
<a id='x1-57228r114'></a><span class='ecrm-0500'>114</span>
|
|
<a id='x1-57230r115'></a><span class='ecrm-0500'>115</span><span class='ectt-0800'>fail1:</span>
|
|
<a id='x1-57232r116'></a><span class='ecrm-0500'>116</span><span class='ectt-0800'> gpio_free_array(leds, ARRAY_SIZE(leds));</span>
|
|
<a id='x1-57234r117'></a><span class='ecrm-0500'>117</span>
|
|
<a id='x1-57236r118'></a><span class='ecrm-0500'>118</span><span class='ectt-0800'> </span><span id='textcolor2435'><span class='ectt-0800'>return</span></span><span class='ectt-0800'> ret;</span>
|
|
<a id='x1-57238r119'></a><span class='ecrm-0500'>119</span><span class='ectt-0800'>}</span>
|
|
<a id='x1-57240r120'></a><span class='ecrm-0500'>120</span>
|
|
<a id='x1-57242r121'></a><span class='ecrm-0500'>121</span><span id='textcolor2436'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor2437'><span class='ectt-0800'>void</span></span><span class='ectt-0800'> __exit intrpt_exit(</span><span id='textcolor2438'><span class='ectt-0800'>void</span></span><span class='ectt-0800'>)</span>
|
|
<a id='x1-57244r122'></a><span class='ecrm-0500'>122</span><span class='ectt-0800'>{</span>
|
|
<a id='x1-57246r123'></a><span class='ecrm-0500'>123</span><span class='ectt-0800'> </span><span id='textcolor2439'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> i;</span>
|
|
<a id='x1-57248r124'></a><span class='ecrm-0500'>124</span>
|
|
<a id='x1-57250r125'></a><span class='ecrm-0500'>125</span><span class='ectt-0800'> pr_info(</span><span id='textcolor2440'><span class='ectt-0800'>"%s</span></span><span id='textcolor2441'><span class='ectt-0800'>\n</span></span><span id='textcolor2442'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>, __func__);</span>
|
|
<a id='x1-57252r126'></a><span class='ecrm-0500'>126</span>
|
|
<a id='x1-57254r127'></a><span class='ecrm-0500'>127</span><span class='ectt-0800'> </span><span id='textcolor2443'><span class='ectt-0800'>/* free irqs */</span></span>
|
|
<a id='x1-57256r128'></a><span class='ecrm-0500'>128</span><span class='ectt-0800'> free_irq(button_irqs[0], NULL);</span>
|
|
<a id='x1-57258r129'></a><span class='ecrm-0500'>129</span><span class='ectt-0800'> free_irq(button_irqs[1], NULL);</span>
|
|
<a id='x1-57260r130'></a><span class='ecrm-0500'>130</span>
|
|
<a id='x1-57262r131'></a><span class='ecrm-0500'>131</span><span class='ectt-0800'> </span><span id='textcolor2444'><span class='ectt-0800'>/* turn all LEDs off */</span></span>
|
|
<a id='x1-57264r132'></a><span class='ecrm-0500'>132</span><span class='ectt-0800'> </span><span id='textcolor2445'><span class='ectt-0800'>for</span></span><span class='ectt-0800'> (i = 0; i < ARRAY_SIZE(leds); i++)</span>
|
|
<a id='x1-57266r133'></a><span class='ecrm-0500'>133</span><span class='ectt-0800'> gpio_set_value(leds[i].gpio, 0);</span>
|
|
<a id='x1-57268r134'></a><span class='ecrm-0500'>134</span>
|
|
<a id='x1-57270r135'></a><span class='ecrm-0500'>135</span><span class='ectt-0800'> </span><span id='textcolor2446'><span class='ectt-0800'>/* unregister */</span></span>
|
|
<a id='x1-57272r136'></a><span class='ecrm-0500'>136</span><span class='ectt-0800'> gpio_free_array(leds, ARRAY_SIZE(leds));</span>
|
|
<a id='x1-57274r137'></a><span class='ecrm-0500'>137</span><span class='ectt-0800'> gpio_free_array(buttons, ARRAY_SIZE(buttons));</span>
|
|
<a id='x1-57276r138'></a><span class='ecrm-0500'>138</span><span class='ectt-0800'>}</span>
|
|
<a id='x1-57278r139'></a><span class='ecrm-0500'>139</span>
|
|
<a id='x1-57280r140'></a><span class='ecrm-0500'>140</span><span class='ectt-0800'>module_init(intrpt_init);</span>
|
|
<a id='x1-57282r141'></a><span class='ecrm-0500'>141</span><span class='ectt-0800'>module_exit(intrpt_exit);</span>
|
|
<a id='x1-57284r142'></a><span class='ecrm-0500'>142</span>
|
|
<a id='x1-57286r143'></a><span class='ecrm-0500'>143</span><span class='ectt-0800'>MODULE_LICENSE(</span><span id='textcolor2447'><span class='ectt-0800'>"GPL"</span></span><span class='ectt-0800'>);</span>
|
|
<a id='x1-57288r144'></a><span class='ecrm-0500'>144</span><span class='ectt-0800'>MODULE_DESCRIPTION(</span><span id='textcolor2448'><span class='ectt-0800'>"Handle some GPIO interrupts"</span></span><span class='ectt-0800'>);</span></pre>
|
|
<!-- l. 1655 --><p class='noindent'>
|
|
</p>
|
|
<h4 class='subsectionHead' id='bottom-half'><span class='titlemark'>15.3 </span> <a id='x1-5800015.3'></a>Bottom Half</h4>
|
|
<!-- l. 1657 --><p class='noindent'>Suppose you want to do a bunch of stuff inside of an interrupt routine. A common
|
|
way to do that without rendering the interrupt unavailable for a significant duration
|
|
is to combine it with a tasklet. This pushes the bulk of the work off into the
|
|
scheduler.
|
|
</p><!-- l. 1661 --><p class='indent'> The example below modifies the previous example to also run an additional task
|
|
when an interrupt is triggered.
|
|
</p><!-- l. 1 --><p class='indent'>
|
|
|
|
|
|
|
|
</p>
|
|
<pre class='fancyvrb' id='fancyvrb69'><a id='x1-58002r1'></a><span class='ecrm-0500'>1</span><span id='textcolor2449'><span class='ectt-0800'>/*</span></span>
|
|
<a id='x1-58004r2'></a><span class='ecrm-0500'>2</span><span id='textcolor2450'><span class='ectt-0800'> * bottomhalf.c - Top and bottom half interrupt handling</span></span>
|
|
<a id='x1-58006r3'></a><span class='ecrm-0500'>3</span><span id='textcolor2451'><span class='ectt-0800'> *</span></span>
|
|
<a id='x1-58008r4'></a><span class='ecrm-0500'>4</span><span id='textcolor2452'><span class='ectt-0800'> * Based upon the RPi example by Stefan Wendler (devnull@kaltpost.de)</span></span>
|
|
<a id='x1-58010r5'></a><span class='ecrm-0500'>5</span><span id='textcolor2453'><span class='ectt-0800'> * from:</span></span>
|
|
<a id='x1-58012r6'></a><span class='ecrm-0500'>6</span><span id='textcolor2454'><span class='ectt-0800'> * https://github.com/wendlers/rpi-kmod-samples</span></span>
|
|
<a id='x1-58014r7'></a><span class='ecrm-0500'>7</span><span id='textcolor2455'><span class='ectt-0800'> *</span></span>
|
|
<a id='x1-58016r8'></a><span class='ecrm-0500'>8</span><span id='textcolor2456'><span class='ectt-0800'> * Press one button to turn on a LED and another to turn it off</span></span>
|
|
<a id='x1-58018r9'></a><span class='ecrm-0500'>9</span><span id='textcolor2457'><span class='ectt-0800'> */</span></span>
|
|
<a id='x1-58020r10'></a><span class='ecrm-0500'>10</span>
|
|
<a id='x1-58022r11'></a><span class='ecrm-0500'>11</span><span id='textcolor2458'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor2459'><span class='ectt-0800'><linux/delay.h></span></span>
|
|
<a id='x1-58024r12'></a><span class='ecrm-0500'>12</span><span id='textcolor2460'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor2461'><span class='ectt-0800'><linux/gpio.h></span></span>
|
|
<a id='x1-58026r13'></a><span class='ecrm-0500'>13</span><span id='textcolor2462'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor2463'><span class='ectt-0800'><linux/interrupt.h></span></span>
|
|
<a id='x1-58028r14'></a><span class='ecrm-0500'>14</span><span id='textcolor2464'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor2465'><span class='ectt-0800'><linux/kernel.h></span></span>
|
|
<a id='x1-58030r15'></a><span class='ecrm-0500'>15</span><span id='textcolor2466'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor2467'><span class='ectt-0800'><linux/module.h></span></span>
|
|
<a id='x1-58032r16'></a><span class='ecrm-0500'>16</span>
|
|
<a id='x1-58034r17'></a><span class='ecrm-0500'>17</span><span id='textcolor2468'><span class='ectt-0800'>/* Macro DECLARE_TASKLET_OLD exists for compatibiity.</span></span>
|
|
<a id='x1-58036r18'></a><span class='ecrm-0500'>18</span><span id='textcolor2469'><span class='ectt-0800'> * See https://lwn.net/Articles/830964/</span></span>
|
|
<a id='x1-58038r19'></a><span class='ecrm-0500'>19</span><span id='textcolor2470'><span class='ectt-0800'> */</span></span>
|
|
<a id='x1-58040r20'></a><span class='ecrm-0500'>20</span><span id='textcolor2471'><span class='ectt-0800'>#ifndef DECLARE_TASKLET_OLD</span></span>
|
|
<a id='x1-58042r21'></a><span class='ecrm-0500'>21</span><span id='textcolor2472'><span class='ectt-0800'>#define DECLARE_TASKLET_OLD(arg1, arg2) DECLARE_TASKLET(arg1, arg2, 0L)</span></span>
|
|
<a id='x1-58044r22'></a><span class='ecrm-0500'>22</span><span id='textcolor2473'><span class='ectt-0800'>#endif</span></span>
|
|
<a id='x1-58046r23'></a><span class='ecrm-0500'>23</span>
|
|
<a id='x1-58048r24'></a><span class='ecrm-0500'>24</span><span id='textcolor2474'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor2475'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> button_irqs[] = { -1, -1 };</span>
|
|
<a id='x1-58050r25'></a><span class='ecrm-0500'>25</span>
|
|
<a id='x1-58052r26'></a><span class='ecrm-0500'>26</span><span id='textcolor2476'><span class='ectt-0800'>/* Define GPIOs for LEDs.</span></span>
|
|
<a id='x1-58054r27'></a><span class='ecrm-0500'>27</span><span id='textcolor2477'><span class='ectt-0800'> * TODO: Change the numbers for the GPIO on your board.</span></span>
|
|
<a id='x1-58056r28'></a><span class='ecrm-0500'>28</span><span id='textcolor2478'><span class='ectt-0800'> */</span></span>
|
|
<a id='x1-58058r29'></a><span class='ecrm-0500'>29</span><span id='textcolor2479'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor2480'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> gpio leds[] = { { 4, GPIOF_OUT_INIT_LOW, </span><span id='textcolor2481'><span class='ectt-0800'>"LED 1"</span></span><span class='ectt-0800'> } };</span>
|
|
<a id='x1-58060r30'></a><span class='ecrm-0500'>30</span>
|
|
<a id='x1-58062r31'></a><span class='ecrm-0500'>31</span><span id='textcolor2482'><span class='ectt-0800'>/* Define GPIOs for BUTTONS</span></span>
|
|
<a id='x1-58064r32'></a><span class='ecrm-0500'>32</span><span id='textcolor2483'><span class='ectt-0800'> * TODO: Change the numbers for the GPIO on your board.</span></span>
|
|
<a id='x1-58066r33'></a><span class='ecrm-0500'>33</span><span id='textcolor2484'><span class='ectt-0800'> */</span></span>
|
|
<a id='x1-58068r34'></a><span class='ecrm-0500'>34</span><span id='textcolor2485'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor2486'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> gpio buttons[] = {</span>
|
|
<a id='x1-58070r35'></a><span class='ecrm-0500'>35</span><span class='ectt-0800'> { 17, GPIOF_IN, </span><span id='textcolor2487'><span class='ectt-0800'>"LED 1 ON BUTTON"</span></span><span class='ectt-0800'> },</span>
|
|
<a id='x1-58072r36'></a><span class='ecrm-0500'>36</span><span class='ectt-0800'> { 18, GPIOF_IN, </span><span id='textcolor2488'><span class='ectt-0800'>"LED 1 OFF BUTTON"</span></span><span class='ectt-0800'> },</span>
|
|
<a id='x1-58074r37'></a><span class='ecrm-0500'>37</span><span class='ectt-0800'>};</span>
|
|
<a id='x1-58076r38'></a><span class='ecrm-0500'>38</span>
|
|
<a id='x1-58078r39'></a><span class='ecrm-0500'>39</span><span id='textcolor2489'><span class='ectt-0800'>/* Tasklet containing some non-trivial amount of processing */</span></span>
|
|
<a id='x1-58080r40'></a><span class='ecrm-0500'>40</span><span id='textcolor2490'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor2491'><span class='ectt-0800'>void</span></span><span class='ectt-0800'> bottomhalf_tasklet_fn(</span><span id='textcolor2492'><span class='ectt-0800'>unsigned</span></span><span class='ectt-0800'> </span><span id='textcolor2493'><span class='ectt-0800'>long</span></span><span class='ectt-0800'> data)</span>
|
|
<a id='x1-58082r41'></a><span class='ecrm-0500'>41</span><span class='ectt-0800'>{</span>
|
|
<a id='x1-58084r42'></a><span class='ecrm-0500'>42</span><span class='ectt-0800'> pr_info(</span><span id='textcolor2494'><span class='ectt-0800'>"Bottom half tasklet starts</span></span><span id='textcolor2495'><span class='ectt-0800'>\n</span></span><span id='textcolor2496'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>);</span>
|
|
<a id='x1-58086r43'></a><span class='ecrm-0500'>43</span><span class='ectt-0800'> </span><span id='textcolor2497'><span class='ectt-0800'>/* do something which takes a while */</span></span>
|
|
<a id='x1-58088r44'></a><span class='ecrm-0500'>44</span><span class='ectt-0800'> mdelay(500);</span>
|
|
<a id='x1-58090r45'></a><span class='ecrm-0500'>45</span><span class='ectt-0800'> pr_info(</span><span id='textcolor2498'><span class='ectt-0800'>"Bottom half tasklet ends</span></span><span id='textcolor2499'><span class='ectt-0800'>\n</span></span><span id='textcolor2500'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>);</span>
|
|
<a id='x1-58092r46'></a><span class='ecrm-0500'>46</span><span class='ectt-0800'>}</span>
|
|
<a id='x1-58094r47'></a><span class='ecrm-0500'>47</span>
|
|
<a id='x1-58096r48'></a><span class='ecrm-0500'>48</span><span id='textcolor2501'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> DECLARE_TASKLET_OLD(buttontask, bottomhalf_tasklet_fn);</span>
|
|
<a id='x1-58098r49'></a><span class='ecrm-0500'>49</span>
|
|
<a id='x1-58100r50'></a><span class='ecrm-0500'>50</span><span id='textcolor2502'><span class='ectt-0800'>/* interrupt function triggered when a button is pressed */</span></span>
|
|
<a id='x1-58102r51'></a><span class='ecrm-0500'>51</span><span id='textcolor2503'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> irqreturn_t button_isr(</span><span id='textcolor2504'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> irq, </span><span id='textcolor2505'><span class='ectt-0800'>void</span></span><span class='ectt-0800'> *data)</span>
|
|
<a id='x1-58104r52'></a><span class='ecrm-0500'>52</span><span class='ectt-0800'>{</span>
|
|
<a id='x1-58106r53'></a><span class='ecrm-0500'>53</span><span class='ectt-0800'> </span><span id='textcolor2506'><span class='ectt-0800'>/* Do something quickly right now */</span></span>
|
|
<a id='x1-58108r54'></a><span class='ecrm-0500'>54</span><span class='ectt-0800'> </span><span id='textcolor2507'><span class='ectt-0800'>if</span></span><span class='ectt-0800'> (irq == button_irqs[0] && !gpio_get_value(leds[0].gpio))</span>
|
|
<a id='x1-58110r55'></a><span class='ecrm-0500'>55</span><span class='ectt-0800'> gpio_set_value(leds[0].gpio, 1);</span>
|
|
<a id='x1-58112r56'></a><span class='ecrm-0500'>56</span><span class='ectt-0800'> </span><span id='textcolor2508'><span class='ectt-0800'>else</span></span><span class='ectt-0800'> </span><span id='textcolor2509'><span class='ectt-0800'>if</span></span><span class='ectt-0800'> (irq == button_irqs[1] && gpio_get_value(leds[0].gpio))</span>
|
|
<a id='x1-58114r57'></a><span class='ecrm-0500'>57</span><span class='ectt-0800'> gpio_set_value(leds[0].gpio, 0);</span>
|
|
<a id='x1-58116r58'></a><span class='ecrm-0500'>58</span>
|
|
<a id='x1-58118r59'></a><span class='ecrm-0500'>59</span><span class='ectt-0800'> </span><span id='textcolor2510'><span class='ectt-0800'>/* Do the rest at leisure via the scheduler */</span></span>
|
|
<a id='x1-58120r60'></a><span class='ecrm-0500'>60</span><span class='ectt-0800'> tasklet_schedule(&buttontask);</span>
|
|
<a id='x1-58122r61'></a><span class='ecrm-0500'>61</span>
|
|
<a id='x1-58124r62'></a><span class='ecrm-0500'>62</span><span class='ectt-0800'> </span><span id='textcolor2511'><span class='ectt-0800'>return</span></span><span class='ectt-0800'> IRQ_HANDLED;</span>
|
|
<a id='x1-58126r63'></a><span class='ecrm-0500'>63</span><span class='ectt-0800'>}</span>
|
|
<a id='x1-58128r64'></a><span class='ecrm-0500'>64</span>
|
|
<a id='x1-58130r65'></a><span class='ecrm-0500'>65</span><span id='textcolor2512'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor2513'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> __init bottomhalf_init(</span><span id='textcolor2514'><span class='ectt-0800'>void</span></span><span class='ectt-0800'>)</span>
|
|
<a id='x1-58132r66'></a><span class='ecrm-0500'>66</span><span class='ectt-0800'>{</span>
|
|
<a id='x1-58134r67'></a><span class='ecrm-0500'>67</span><span class='ectt-0800'> </span><span id='textcolor2515'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> ret = 0;</span>
|
|
<a id='x1-58136r68'></a><span class='ecrm-0500'>68</span>
|
|
<a id='x1-58138r69'></a><span class='ecrm-0500'>69</span><span class='ectt-0800'> pr_info(</span><span id='textcolor2516'><span class='ectt-0800'>"%s</span></span><span id='textcolor2517'><span class='ectt-0800'>\n</span></span><span id='textcolor2518'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>, __func__);</span>
|
|
<a id='x1-58140r70'></a><span class='ecrm-0500'>70</span>
|
|
<a id='x1-58142r71'></a><span class='ecrm-0500'>71</span><span class='ectt-0800'> </span><span id='textcolor2519'><span class='ectt-0800'>/* register LED gpios */</span></span>
|
|
<a id='x1-58144r72'></a><span class='ecrm-0500'>72</span><span class='ectt-0800'> ret = gpio_request_array(leds, ARRAY_SIZE(leds));</span>
|
|
<a id='x1-58146r73'></a><span class='ecrm-0500'>73</span>
|
|
<a id='x1-58148r74'></a><span class='ecrm-0500'>74</span><span class='ectt-0800'> </span><span id='textcolor2520'><span class='ectt-0800'>if</span></span><span class='ectt-0800'> (ret) {</span>
|
|
<a id='x1-58150r75'></a><span class='ecrm-0500'>75</span><span class='ectt-0800'> pr_err(</span><span id='textcolor2521'><span class='ectt-0800'>"Unable to request GPIOs for LEDs: %d</span></span><span id='textcolor2522'><span class='ectt-0800'>\n</span></span><span id='textcolor2523'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>, ret);</span>
|
|
<a id='x1-58152r76'></a><span class='ecrm-0500'>76</span><span class='ectt-0800'> </span><span id='textcolor2524'><span class='ectt-0800'>return</span></span><span class='ectt-0800'> ret;</span>
|
|
<a id='x1-58154r77'></a><span class='ecrm-0500'>77</span><span class='ectt-0800'> }</span>
|
|
<a id='x1-58156r78'></a><span class='ecrm-0500'>78</span>
|
|
<a id='x1-58158r79'></a><span class='ecrm-0500'>79</span><span class='ectt-0800'> </span><span id='textcolor2525'><span class='ectt-0800'>/* register BUTTON gpios */</span></span>
|
|
<a id='x1-58160r80'></a><span class='ecrm-0500'>80</span><span class='ectt-0800'> ret = gpio_request_array(buttons, ARRAY_SIZE(buttons));</span>
|
|
<a id='x1-58162r81'></a><span class='ecrm-0500'>81</span>
|
|
<a id='x1-58164r82'></a><span class='ecrm-0500'>82</span><span class='ectt-0800'> </span><span id='textcolor2526'><span class='ectt-0800'>if</span></span><span class='ectt-0800'> (ret) {</span>
|
|
<a id='x1-58166r83'></a><span class='ecrm-0500'>83</span><span class='ectt-0800'> pr_err(</span><span id='textcolor2527'><span class='ectt-0800'>"Unable to request GPIOs for BUTTONs: %d</span></span><span id='textcolor2528'><span class='ectt-0800'>\n</span></span><span id='textcolor2529'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>, ret);</span>
|
|
<a id='x1-58168r84'></a><span class='ecrm-0500'>84</span><span class='ectt-0800'> </span><span id='textcolor2530'><span class='ectt-0800'>goto</span></span><span class='ectt-0800'> fail1;</span>
|
|
<a id='x1-58170r85'></a><span class='ecrm-0500'>85</span><span class='ectt-0800'> }</span>
|
|
<a id='x1-58172r86'></a><span class='ecrm-0500'>86</span>
|
|
<a id='x1-58174r87'></a><span class='ecrm-0500'>87</span><span class='ectt-0800'> pr_info(</span><span id='textcolor2531'><span class='ectt-0800'>"Current button1 value: %d</span></span><span id='textcolor2532'><span class='ectt-0800'>\n</span></span><span id='textcolor2533'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>, gpio_get_value(buttons[0].gpio));</span>
|
|
<a id='x1-58176r88'></a><span class='ecrm-0500'>88</span>
|
|
<a id='x1-58178r89'></a><span class='ecrm-0500'>89</span><span class='ectt-0800'> ret = gpio_to_irq(buttons[0].gpio);</span>
|
|
<a id='x1-58180r90'></a><span class='ecrm-0500'>90</span>
|
|
<a id='x1-58182r91'></a><span class='ecrm-0500'>91</span><span class='ectt-0800'> </span><span id='textcolor2534'><span class='ectt-0800'>if</span></span><span class='ectt-0800'> (ret < 0) {</span>
|
|
<a id='x1-58184r92'></a><span class='ecrm-0500'>92</span><span class='ectt-0800'> pr_err(</span><span id='textcolor2535'><span class='ectt-0800'>"Unable to request IRQ: %d</span></span><span id='textcolor2536'><span class='ectt-0800'>\n</span></span><span id='textcolor2537'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>, ret);</span>
|
|
<a id='x1-58186r93'></a><span class='ecrm-0500'>93</span><span class='ectt-0800'> </span><span id='textcolor2538'><span class='ectt-0800'>goto</span></span><span class='ectt-0800'> fail2;</span>
|
|
<a id='x1-58188r94'></a><span class='ecrm-0500'>94</span><span class='ectt-0800'> }</span>
|
|
<a id='x1-58190r95'></a><span class='ecrm-0500'>95</span>
|
|
<a id='x1-58192r96'></a><span class='ecrm-0500'>96</span><span class='ectt-0800'> button_irqs[0] = ret;</span>
|
|
<a id='x1-58194r97'></a><span class='ecrm-0500'>97</span>
|
|
<a id='x1-58196r98'></a><span class='ecrm-0500'>98</span><span class='ectt-0800'> pr_info(</span><span id='textcolor2539'><span class='ectt-0800'>"Successfully requested BUTTON1 IRQ # %d</span></span><span id='textcolor2540'><span class='ectt-0800'>\n</span></span><span id='textcolor2541'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>, button_irqs[0]);</span>
|
|
<a id='x1-58198r99'></a><span class='ecrm-0500'>99</span>
|
|
<a id='x1-58200r100'></a><span class='ecrm-0500'>100</span><span class='ectt-0800'> ret = request_irq(button_irqs[0], button_isr,</span>
|
|
<a id='x1-58202r101'></a><span class='ecrm-0500'>101</span><span class='ectt-0800'> IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,</span>
|
|
<a id='x1-58204r102'></a><span class='ecrm-0500'>102</span><span class='ectt-0800'> </span><span id='textcolor2542'><span class='ectt-0800'>"gpiomod#button1"</span></span><span class='ectt-0800'>, NULL);</span>
|
|
<a id='x1-58206r103'></a><span class='ecrm-0500'>103</span>
|
|
<a id='x1-58208r104'></a><span class='ecrm-0500'>104</span><span class='ectt-0800'> </span><span id='textcolor2543'><span class='ectt-0800'>if</span></span><span class='ectt-0800'> (ret) {</span>
|
|
<a id='x1-58210r105'></a><span class='ecrm-0500'>105</span><span class='ectt-0800'> pr_err(</span><span id='textcolor2544'><span class='ectt-0800'>"Unable to request IRQ: %d</span></span><span id='textcolor2545'><span class='ectt-0800'>\n</span></span><span id='textcolor2546'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>, ret);</span>
|
|
<a id='x1-58212r106'></a><span class='ecrm-0500'>106</span><span class='ectt-0800'> </span><span id='textcolor2547'><span class='ectt-0800'>goto</span></span><span class='ectt-0800'> fail2;</span>
|
|
<a id='x1-58214r107'></a><span class='ecrm-0500'>107</span><span class='ectt-0800'> }</span>
|
|
<a id='x1-58216r108'></a><span class='ecrm-0500'>108</span>
|
|
<a id='x1-58218r109'></a><span class='ecrm-0500'>109</span><span class='ectt-0800'> ret = gpio_to_irq(buttons[1].gpio);</span>
|
|
<a id='x1-58220r110'></a><span class='ecrm-0500'>110</span>
|
|
<a id='x1-58222r111'></a><span class='ecrm-0500'>111</span><span class='ectt-0800'> </span><span id='textcolor2548'><span class='ectt-0800'>if</span></span><span class='ectt-0800'> (ret < 0) {</span>
|
|
<a id='x1-58224r112'></a><span class='ecrm-0500'>112</span><span class='ectt-0800'> pr_err(</span><span id='textcolor2549'><span class='ectt-0800'>"Unable to request IRQ: %d</span></span><span id='textcolor2550'><span class='ectt-0800'>\n</span></span><span id='textcolor2551'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>, ret);</span>
|
|
<a id='x1-58226r113'></a><span class='ecrm-0500'>113</span><span class='ectt-0800'> </span><span id='textcolor2552'><span class='ectt-0800'>goto</span></span><span class='ectt-0800'> fail2;</span>
|
|
<a id='x1-58228r114'></a><span class='ecrm-0500'>114</span><span class='ectt-0800'> }</span>
|
|
<a id='x1-58230r115'></a><span class='ecrm-0500'>115</span>
|
|
<a id='x1-58232r116'></a><span class='ecrm-0500'>116</span><span class='ectt-0800'> button_irqs[1] = ret;</span>
|
|
<a id='x1-58234r117'></a><span class='ecrm-0500'>117</span>
|
|
<a id='x1-58236r118'></a><span class='ecrm-0500'>118</span><span class='ectt-0800'> pr_info(</span><span id='textcolor2553'><span class='ectt-0800'>"Successfully requested BUTTON2 IRQ # %d</span></span><span id='textcolor2554'><span class='ectt-0800'>\n</span></span><span id='textcolor2555'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>, button_irqs[1]);</span>
|
|
<a id='x1-58238r119'></a><span class='ecrm-0500'>119</span>
|
|
<a id='x1-58240r120'></a><span class='ecrm-0500'>120</span><span class='ectt-0800'> ret = request_irq(button_irqs[1], button_isr,</span>
|
|
<a id='x1-58242r121'></a><span class='ecrm-0500'>121</span><span class='ectt-0800'> IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,</span>
|
|
<a id='x1-58244r122'></a><span class='ecrm-0500'>122</span><span class='ectt-0800'> </span><span id='textcolor2556'><span class='ectt-0800'>"gpiomod#button2"</span></span><span class='ectt-0800'>, NULL);</span>
|
|
<a id='x1-58246r123'></a><span class='ecrm-0500'>123</span>
|
|
<a id='x1-58248r124'></a><span class='ecrm-0500'>124</span><span class='ectt-0800'> </span><span id='textcolor2557'><span class='ectt-0800'>if</span></span><span class='ectt-0800'> (ret) {</span>
|
|
<a id='x1-58250r125'></a><span class='ecrm-0500'>125</span><span class='ectt-0800'> pr_err(</span><span id='textcolor2558'><span class='ectt-0800'>"Unable to request IRQ: %d</span></span><span id='textcolor2559'><span class='ectt-0800'>\n</span></span><span id='textcolor2560'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>, ret);</span>
|
|
<a id='x1-58252r126'></a><span class='ecrm-0500'>126</span><span class='ectt-0800'> </span><span id='textcolor2561'><span class='ectt-0800'>goto</span></span><span class='ectt-0800'> fail3;</span>
|
|
<a id='x1-58254r127'></a><span class='ecrm-0500'>127</span><span class='ectt-0800'> }</span>
|
|
<a id='x1-58256r128'></a><span class='ecrm-0500'>128</span>
|
|
<a id='x1-58258r129'></a><span class='ecrm-0500'>129</span><span class='ectt-0800'> </span><span id='textcolor2562'><span class='ectt-0800'>return</span></span><span class='ectt-0800'> 0;</span>
|
|
<a id='x1-58260r130'></a><span class='ecrm-0500'>130</span>
|
|
<a id='x1-58262r131'></a><span class='ecrm-0500'>131</span><span id='textcolor2563'><span class='ectt-0800'>/* cleanup what has been setup so far */</span></span>
|
|
<a id='x1-58264r132'></a><span class='ecrm-0500'>132</span><span class='ectt-0800'>fail3:</span>
|
|
<a id='x1-58266r133'></a><span class='ecrm-0500'>133</span><span class='ectt-0800'> free_irq(button_irqs[0], NULL);</span>
|
|
<a id='x1-58268r134'></a><span class='ecrm-0500'>134</span>
|
|
<a id='x1-58270r135'></a><span class='ecrm-0500'>135</span><span class='ectt-0800'>fail2:</span>
|
|
<a id='x1-58272r136'></a><span class='ecrm-0500'>136</span><span class='ectt-0800'> gpio_free_array(buttons, ARRAY_SIZE(leds));</span>
|
|
<a id='x1-58274r137'></a><span class='ecrm-0500'>137</span>
|
|
<a id='x1-58276r138'></a><span class='ecrm-0500'>138</span><span class='ectt-0800'>fail1:</span>
|
|
<a id='x1-58278r139'></a><span class='ecrm-0500'>139</span><span class='ectt-0800'> gpio_free_array(leds, ARRAY_SIZE(leds));</span>
|
|
<a id='x1-58280r140'></a><span class='ecrm-0500'>140</span>
|
|
<a id='x1-58282r141'></a><span class='ecrm-0500'>141</span><span class='ectt-0800'> </span><span id='textcolor2564'><span class='ectt-0800'>return</span></span><span class='ectt-0800'> ret;</span>
|
|
<a id='x1-58284r142'></a><span class='ecrm-0500'>142</span><span class='ectt-0800'>}</span>
|
|
<a id='x1-58286r143'></a><span class='ecrm-0500'>143</span>
|
|
<a id='x1-58288r144'></a><span class='ecrm-0500'>144</span><span id='textcolor2565'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor2566'><span class='ectt-0800'>void</span></span><span class='ectt-0800'> __exit bottomhalf_exit(</span><span id='textcolor2567'><span class='ectt-0800'>void</span></span><span class='ectt-0800'>)</span>
|
|
<a id='x1-58290r145'></a><span class='ecrm-0500'>145</span><span class='ectt-0800'>{</span>
|
|
<a id='x1-58292r146'></a><span class='ecrm-0500'>146</span><span class='ectt-0800'> </span><span id='textcolor2568'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> i;</span>
|
|
<a id='x1-58294r147'></a><span class='ecrm-0500'>147</span>
|
|
<a id='x1-58296r148'></a><span class='ecrm-0500'>148</span><span class='ectt-0800'> pr_info(</span><span id='textcolor2569'><span class='ectt-0800'>"%s</span></span><span id='textcolor2570'><span class='ectt-0800'>\n</span></span><span id='textcolor2571'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>, __func__);</span>
|
|
<a id='x1-58298r149'></a><span class='ecrm-0500'>149</span>
|
|
<a id='x1-58300r150'></a><span class='ecrm-0500'>150</span><span class='ectt-0800'> </span><span id='textcolor2572'><span class='ectt-0800'>/* free irqs */</span></span>
|
|
<a id='x1-58302r151'></a><span class='ecrm-0500'>151</span><span class='ectt-0800'> free_irq(button_irqs[0], NULL);</span>
|
|
<a id='x1-58304r152'></a><span class='ecrm-0500'>152</span><span class='ectt-0800'> free_irq(button_irqs[1], NULL);</span>
|
|
<a id='x1-58306r153'></a><span class='ecrm-0500'>153</span>
|
|
<a id='x1-58308r154'></a><span class='ecrm-0500'>154</span><span class='ectt-0800'> </span><span id='textcolor2573'><span class='ectt-0800'>/* turn all LEDs off */</span></span>
|
|
<a id='x1-58310r155'></a><span class='ecrm-0500'>155</span><span class='ectt-0800'> </span><span id='textcolor2574'><span class='ectt-0800'>for</span></span><span class='ectt-0800'> (i = 0; i < ARRAY_SIZE(leds); i++)</span>
|
|
<a id='x1-58312r156'></a><span class='ecrm-0500'>156</span><span class='ectt-0800'> gpio_set_value(leds[i].gpio, 0);</span>
|
|
<a id='x1-58314r157'></a><span class='ecrm-0500'>157</span>
|
|
<a id='x1-58316r158'></a><span class='ecrm-0500'>158</span><span class='ectt-0800'> </span><span id='textcolor2575'><span class='ectt-0800'>/* unregister */</span></span>
|
|
<a id='x1-58318r159'></a><span class='ecrm-0500'>159</span><span class='ectt-0800'> gpio_free_array(leds, ARRAY_SIZE(leds));</span>
|
|
<a id='x1-58320r160'></a><span class='ecrm-0500'>160</span><span class='ectt-0800'> gpio_free_array(buttons, ARRAY_SIZE(buttons));</span>
|
|
<a id='x1-58322r161'></a><span class='ecrm-0500'>161</span><span class='ectt-0800'>}</span>
|
|
<a id='x1-58324r162'></a><span class='ecrm-0500'>162</span>
|
|
<a id='x1-58326r163'></a><span class='ecrm-0500'>163</span><span class='ectt-0800'>module_init(bottomhalf_init);</span>
|
|
<a id='x1-58328r164'></a><span class='ecrm-0500'>164</span><span class='ectt-0800'>module_exit(bottomhalf_exit);</span>
|
|
<a id='x1-58330r165'></a><span class='ecrm-0500'>165</span>
|
|
<a id='x1-58332r166'></a><span class='ecrm-0500'>166</span><span class='ectt-0800'>MODULE_LICENSE(</span><span id='textcolor2576'><span class='ectt-0800'>"GPL"</span></span><span class='ectt-0800'>);</span>
|
|
<a id='x1-58334r167'></a><span class='ecrm-0500'>167</span><span class='ectt-0800'>MODULE_DESCRIPTION(</span><span id='textcolor2577'><span class='ectt-0800'>"Interrupt with top and bottom half"</span></span><span class='ectt-0800'>);</span></pre>
|
|
<!-- l. 1665 --><p class='noindent'>
|
|
</p>
|
|
<h3 class='sectionHead' id='crypto'><span class='titlemark'>16 </span> <a id='x1-5900016'></a>Crypto</h3>
|
|
<!-- l. 1667 --><p class='noindent'>At the dawn of the internet, everybody trusted everybody completely…but that did
|
|
not work out so well. When this guide was originally written, it was a more innocent
|
|
era in which almost nobody actually gave a damn about crypto - least of all kernel
|
|
developers. That is certainly no longer the case now. To handle crypto stuff, the
|
|
kernel has its own API enabling common methods of encryption, decryption and your
|
|
favourite hash functions.
|
|
</p><!-- l. 1672 --><p class='noindent'>
|
|
</p>
|
|
<h4 class='subsectionHead' id='hash-functions'><span class='titlemark'>16.1 </span> <a id='x1-6000016.1'></a>Hash functions</h4>
|
|
<!-- l. 1675 --><p class='noindent'>Calculating and checking the hashes of things is a common operation. Here is a
|
|
demonstration of how to calculate a sha256 hash within a kernel module.
|
|
</p><!-- l. 1 --><p class='indent'>
|
|
</p>
|
|
<pre class='fancyvrb' id='fancyvrb70'><a id='x1-60002r1'></a><span class='ecrm-0500'>1</span><span id='textcolor2578'><span class='ectt-0800'>/*</span></span>
|
|
<a id='x1-60004r2'></a><span class='ecrm-0500'>2</span><span id='textcolor2579'><span class='ectt-0800'> * cryptosha256.c</span></span>
|
|
<a id='x1-60006r3'></a><span class='ecrm-0500'>3</span><span id='textcolor2580'><span class='ectt-0800'> */</span></span>
|
|
<a id='x1-60008r4'></a><span class='ecrm-0500'>4</span><span id='textcolor2581'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor2582'><span class='ectt-0800'><crypto/internal/hash.h></span></span>
|
|
<a id='x1-60010r5'></a><span class='ecrm-0500'>5</span><span id='textcolor2583'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor2584'><span class='ectt-0800'><linux/module.h></span></span>
|
|
<a id='x1-60012r6'></a><span class='ecrm-0500'>6</span>
|
|
<a id='x1-60014r7'></a><span class='ecrm-0500'>7</span><span id='textcolor2585'><span class='ectt-0800'>#define SHA256_LENGTH 32</span></span>
|
|
<a id='x1-60016r8'></a><span class='ecrm-0500'>8</span>
|
|
<a id='x1-60018r9'></a><span class='ecrm-0500'>9</span><span id='textcolor2586'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor2587'><span class='ectt-0800'>void</span></span><span class='ectt-0800'> show_hash_result(</span><span id='textcolor2588'><span class='ectt-0800'>char</span></span><span class='ectt-0800'> *plaintext, </span><span id='textcolor2589'><span class='ectt-0800'>char</span></span><span class='ectt-0800'> *hash_sha256)</span>
|
|
<a id='x1-60020r10'></a><span class='ecrm-0500'>10</span><span class='ectt-0800'>{</span>
|
|
<a id='x1-60022r11'></a><span class='ecrm-0500'>11</span><span class='ectt-0800'> </span><span id='textcolor2590'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> i;</span>
|
|
<a id='x1-60024r12'></a><span class='ecrm-0500'>12</span><span class='ectt-0800'> </span><span id='textcolor2591'><span class='ectt-0800'>char</span></span><span class='ectt-0800'> str[SHA256_LENGTH * 2 + 1];</span>
|
|
<a id='x1-60026r13'></a><span class='ecrm-0500'>13</span>
|
|
<a id='x1-60028r14'></a><span class='ecrm-0500'>14</span><span class='ectt-0800'> pr_info(</span><span id='textcolor2592'><span class='ectt-0800'>"sha256 test for string: </span></span><span id='textcolor2593'><span class='ectt-0800'>\"</span></span><span id='textcolor2594'><span class='ectt-0800'>%s</span></span><span id='textcolor2595'><span class='ectt-0800'>\"\n</span></span><span id='textcolor2596'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>, plaintext);</span>
|
|
<a id='x1-60030r15'></a><span class='ecrm-0500'>15</span><span class='ectt-0800'> </span><span id='textcolor2597'><span class='ectt-0800'>for</span></span><span class='ectt-0800'> (i = 0; i < SHA256_LENGTH; i++)</span>
|
|
<a id='x1-60032r16'></a><span class='ecrm-0500'>16</span><span class='ectt-0800'> sprintf(&str[i * 2], </span><span id='textcolor2598'><span class='ectt-0800'>"%02x"</span></span><span class='ectt-0800'>, (</span><span id='textcolor2599'><span class='ectt-0800'>unsigned</span></span><span class='ectt-0800'> </span><span id='textcolor2600'><span class='ectt-0800'>char</span></span><span class='ectt-0800'>)hash_sha256[i]);</span>
|
|
<a id='x1-60034r17'></a><span class='ecrm-0500'>17</span><span class='ectt-0800'> str[i * 2] = 0;</span>
|
|
<a id='x1-60036r18'></a><span class='ecrm-0500'>18</span><span class='ectt-0800'> pr_info(</span><span id='textcolor2601'><span class='ectt-0800'>"%s</span></span><span id='textcolor2602'><span class='ectt-0800'>\n</span></span><span id='textcolor2603'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>, str);</span>
|
|
<a id='x1-60038r19'></a><span class='ecrm-0500'>19</span><span class='ectt-0800'>}</span>
|
|
<a id='x1-60040r20'></a><span class='ecrm-0500'>20</span>
|
|
<a id='x1-60042r21'></a><span class='ecrm-0500'>21</span><span id='textcolor2604'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor2605'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> cryptosha256_init(</span><span id='textcolor2606'><span class='ectt-0800'>void</span></span><span class='ectt-0800'>)</span>
|
|
<a id='x1-60044r22'></a><span class='ecrm-0500'>22</span><span class='ectt-0800'>{</span>
|
|
<a id='x1-60046r23'></a><span class='ecrm-0500'>23</span><span class='ectt-0800'> </span><span id='textcolor2607'><span class='ectt-0800'>char</span></span><span class='ectt-0800'> *plaintext = </span><span id='textcolor2608'><span class='ectt-0800'>"This is a test"</span></span><span class='ectt-0800'>;</span>
|
|
<a id='x1-60048r24'></a><span class='ecrm-0500'>24</span><span class='ectt-0800'> </span><span id='textcolor2609'><span class='ectt-0800'>char</span></span><span class='ectt-0800'> hash_sha256[SHA256_LENGTH];</span>
|
|
<a id='x1-60050r25'></a><span class='ecrm-0500'>25</span><span class='ectt-0800'> </span><span id='textcolor2610'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> crypto_shash *sha256;</span>
|
|
<a id='x1-60052r26'></a><span class='ecrm-0500'>26</span><span class='ectt-0800'> </span><span id='textcolor2611'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> shash_desc *shash;</span>
|
|
<a id='x1-60054r27'></a><span class='ecrm-0500'>27</span>
|
|
<a id='x1-60056r28'></a><span class='ecrm-0500'>28</span><span class='ectt-0800'> sha256 = crypto_alloc_shash(</span><span id='textcolor2612'><span class='ectt-0800'>"sha256"</span></span><span class='ectt-0800'>, 0, 0);</span>
|
|
<a id='x1-60058r29'></a><span class='ecrm-0500'>29</span><span class='ectt-0800'> </span><span id='textcolor2613'><span class='ectt-0800'>if</span></span><span class='ectt-0800'> (IS_ERR(sha256))</span>
|
|
<a id='x1-60060r30'></a><span class='ecrm-0500'>30</span><span class='ectt-0800'> </span><span id='textcolor2614'><span class='ectt-0800'>return</span></span><span class='ectt-0800'> -1;</span>
|
|
<a id='x1-60062r31'></a><span class='ecrm-0500'>31</span>
|
|
<a id='x1-60064r32'></a><span class='ecrm-0500'>32</span><span class='ectt-0800'> shash = kmalloc(</span><span id='textcolor2615'><span class='ectt-0800'>sizeof</span></span><span class='ectt-0800'>(</span><span id='textcolor2616'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> shash_desc) + crypto_shash_descsize(sha256),</span>
|
|
<a id='x1-60066r33'></a><span class='ecrm-0500'>33</span><span class='ectt-0800'> GFP_KERNEL);</span>
|
|
<a id='x1-60068r34'></a><span class='ecrm-0500'>34</span><span class='ectt-0800'> </span><span id='textcolor2617'><span class='ectt-0800'>if</span></span><span class='ectt-0800'> (!shash)</span>
|
|
<a id='x1-60070r35'></a><span class='ecrm-0500'>35</span><span class='ectt-0800'> </span><span id='textcolor2618'><span class='ectt-0800'>return</span></span><span class='ectt-0800'> -ENOMEM;</span>
|
|
<a id='x1-60072r36'></a><span class='ecrm-0500'>36</span>
|
|
<a id='x1-60074r37'></a><span class='ecrm-0500'>37</span><span class='ectt-0800'> shash->tfm = sha256;</span>
|
|
<a id='x1-60076r38'></a><span class='ecrm-0500'>38</span>
|
|
<a id='x1-60078r39'></a><span class='ecrm-0500'>39</span><span class='ectt-0800'> </span><span id='textcolor2619'><span class='ectt-0800'>if</span></span><span class='ectt-0800'> (crypto_shash_init(shash))</span>
|
|
<a id='x1-60080r40'></a><span class='ecrm-0500'>40</span><span class='ectt-0800'> </span><span id='textcolor2620'><span class='ectt-0800'>return</span></span><span class='ectt-0800'> -1;</span>
|
|
<a id='x1-60082r41'></a><span class='ecrm-0500'>41</span>
|
|
<a id='x1-60084r42'></a><span class='ecrm-0500'>42</span><span class='ectt-0800'> </span><span id='textcolor2621'><span class='ectt-0800'>if</span></span><span class='ectt-0800'> (crypto_shash_update(shash, plaintext, strlen(plaintext)))</span>
|
|
<a id='x1-60086r43'></a><span class='ecrm-0500'>43</span><span class='ectt-0800'> </span><span id='textcolor2622'><span class='ectt-0800'>return</span></span><span class='ectt-0800'> -1;</span>
|
|
<a id='x1-60088r44'></a><span class='ecrm-0500'>44</span>
|
|
<a id='x1-60090r45'></a><span class='ecrm-0500'>45</span><span class='ectt-0800'> </span><span id='textcolor2623'><span class='ectt-0800'>if</span></span><span class='ectt-0800'> (crypto_shash_final(shash, hash_sha256))</span>
|
|
<a id='x1-60092r46'></a><span class='ecrm-0500'>46</span><span class='ectt-0800'> </span><span id='textcolor2624'><span class='ectt-0800'>return</span></span><span class='ectt-0800'> -1;</span>
|
|
<a id='x1-60094r47'></a><span class='ecrm-0500'>47</span>
|
|
<a id='x1-60096r48'></a><span class='ecrm-0500'>48</span><span class='ectt-0800'> kfree(shash);</span>
|
|
<a id='x1-60098r49'></a><span class='ecrm-0500'>49</span><span class='ectt-0800'> crypto_free_shash(sha256);</span>
|
|
<a id='x1-60100r50'></a><span class='ecrm-0500'>50</span>
|
|
<a id='x1-60102r51'></a><span class='ecrm-0500'>51</span><span class='ectt-0800'> show_hash_result(plaintext, hash_sha256);</span>
|
|
<a id='x1-60104r52'></a><span class='ecrm-0500'>52</span>
|
|
<a id='x1-60106r53'></a><span class='ecrm-0500'>53</span><span class='ectt-0800'> </span><span id='textcolor2625'><span class='ectt-0800'>return</span></span><span class='ectt-0800'> 0;</span>
|
|
<a id='x1-60108r54'></a><span class='ecrm-0500'>54</span><span class='ectt-0800'>}</span>
|
|
<a id='x1-60110r55'></a><span class='ecrm-0500'>55</span>
|
|
<a id='x1-60112r56'></a><span class='ecrm-0500'>56</span><span id='textcolor2626'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor2627'><span class='ectt-0800'>void</span></span><span class='ectt-0800'> cryptosha256_exit(</span><span id='textcolor2628'><span class='ectt-0800'>void</span></span><span class='ectt-0800'>)</span>
|
|
<a id='x1-60114r57'></a><span class='ecrm-0500'>57</span><span class='ectt-0800'>{</span>
|
|
<a id='x1-60116r58'></a><span class='ecrm-0500'>58</span><span class='ectt-0800'>}</span>
|
|
<a id='x1-60118r59'></a><span class='ecrm-0500'>59</span>
|
|
<a id='x1-60120r60'></a><span class='ecrm-0500'>60</span><span class='ectt-0800'>module_init(cryptosha256_init);</span>
|
|
<a id='x1-60122r61'></a><span class='ecrm-0500'>61</span><span class='ectt-0800'>module_exit(cryptosha256_exit);</span>
|
|
<a id='x1-60124r62'></a><span class='ecrm-0500'>62</span>
|
|
<a id='x1-60126r63'></a><span class='ecrm-0500'>63</span><span class='ectt-0800'>MODULE_DESCRIPTION(</span><span id='textcolor2629'><span class='ectt-0800'>"sha256 hash test"</span></span><span class='ectt-0800'>);</span>
|
|
<a id='x1-60128r64'></a><span class='ecrm-0500'>64</span><span class='ectt-0800'>MODULE_LICENSE(</span><span id='textcolor2630'><span class='ectt-0800'>"GPL"</span></span><span class='ectt-0800'>);</span></pre>
|
|
<!-- l. 1680 --><p class='indent'> Make and install the module:
|
|
</p><!-- l. 1 --><p class='indent'>
|
|
</p>
|
|
<pre class='fancyvrb' id='fancyvrb71'><a id='x1-60133r1'></a><span class='ecrm-0500'>1</span><span class='ectt-1000'>make</span>
|
|
<a id='x1-60135r2'></a><span class='ecrm-0500'>2</span><span class='ectt-1000'>sudo insmod cryptosha256.ko</span>
|
|
<a id='x1-60137r3'></a><span class='ecrm-0500'>3</span><span class='ectt-1000'>dmesg</span></pre>
|
|
<!-- l. 1688 --><p class='indent'> And you should see that the hash was calculated for the test string.
|
|
</p><!-- l. 1690 --><p class='indent'> Finally, remove the test module:
|
|
</p><!-- l. 1 --><p class='indent'>
|
|
</p>
|
|
<pre class='fancyvrb' id='fancyvrb72'><a id='x1-60140r1'></a><span class='ecrm-0500'>1</span><span class='ectt-1000'>sudo rmmod cryptosha256</span></pre>
|
|
<!-- l. 1696 --><p class='noindent'>
|
|
</p>
|
|
<h4 class='subsectionHead' id='symmetric-key-encryption'><span class='titlemark'>16.2 </span> <a id='x1-6100016.2'></a>Symmetric key encryption</h4>
|
|
<!-- l. 1698 --><p class='noindent'>Here is an example of symmetrically encrypting a string using the AES algorithm
|
|
and a password.
|
|
</p><!-- l. 1 --><p class='indent'>
|
|
|
|
|
|
|
|
</p>
|
|
<pre class='fancyvrb' id='fancyvrb73'><a id='x1-61002r1'></a><span class='ecrm-0500'>1</span><span id='textcolor2631'><span class='ectt-0800'>/*</span></span>
|
|
<a id='x1-61004r2'></a><span class='ecrm-0500'>2</span><span id='textcolor2632'><span class='ectt-0800'> * cryptosk.c</span></span>
|
|
<a id='x1-61006r3'></a><span class='ecrm-0500'>3</span><span id='textcolor2633'><span class='ectt-0800'> */</span></span>
|
|
<a id='x1-61008r4'></a><span class='ecrm-0500'>4</span><span id='textcolor2634'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor2635'><span class='ectt-0800'><crypto/internal/skcipher.h></span></span>
|
|
<a id='x1-61010r5'></a><span class='ecrm-0500'>5</span><span id='textcolor2636'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor2637'><span class='ectt-0800'><linux/crypto.h></span></span>
|
|
<a id='x1-61012r6'></a><span class='ecrm-0500'>6</span><span id='textcolor2638'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor2639'><span class='ectt-0800'><linux/module.h></span></span>
|
|
<a id='x1-61014r7'></a><span class='ecrm-0500'>7</span><span id='textcolor2640'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor2641'><span class='ectt-0800'><linux/random.h></span></span>
|
|
<a id='x1-61016r8'></a><span class='ecrm-0500'>8</span><span id='textcolor2642'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor2643'><span class='ectt-0800'><linux/scatterlist.h></span></span>
|
|
<a id='x1-61018r9'></a><span class='ecrm-0500'>9</span>
|
|
<a id='x1-61020r10'></a><span class='ecrm-0500'>10</span><span id='textcolor2644'><span class='ectt-0800'>#define SYMMETRIC_KEY_LENGTH 32</span></span>
|
|
<a id='x1-61022r11'></a><span class='ecrm-0500'>11</span><span id='textcolor2645'><span class='ectt-0800'>#define CIPHER_BLOCK_SIZE 16</span></span>
|
|
<a id='x1-61024r12'></a><span class='ecrm-0500'>12</span>
|
|
<a id='x1-61026r13'></a><span class='ecrm-0500'>13</span><span id='textcolor2646'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> tcrypt_result {</span>
|
|
<a id='x1-61028r14'></a><span class='ecrm-0500'>14</span><span class='ectt-0800'> </span><span id='textcolor2647'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> completion completion;</span>
|
|
<a id='x1-61030r15'></a><span class='ecrm-0500'>15</span><span class='ectt-0800'> </span><span id='textcolor2648'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> err;</span>
|
|
<a id='x1-61032r16'></a><span class='ecrm-0500'>16</span><span class='ectt-0800'>};</span>
|
|
<a id='x1-61034r17'></a><span class='ecrm-0500'>17</span>
|
|
<a id='x1-61036r18'></a><span class='ecrm-0500'>18</span><span id='textcolor2649'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> skcipher_def {</span>
|
|
<a id='x1-61038r19'></a><span class='ecrm-0500'>19</span><span class='ectt-0800'> </span><span id='textcolor2650'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> scatterlist sg;</span>
|
|
<a id='x1-61040r20'></a><span class='ecrm-0500'>20</span><span class='ectt-0800'> </span><span id='textcolor2651'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> crypto_skcipher *tfm;</span>
|
|
<a id='x1-61042r21'></a><span class='ecrm-0500'>21</span><span class='ectt-0800'> </span><span id='textcolor2652'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> skcipher_request *req;</span>
|
|
<a id='x1-61044r22'></a><span class='ecrm-0500'>22</span><span class='ectt-0800'> </span><span id='textcolor2653'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> tcrypt_result result;</span>
|
|
<a id='x1-61046r23'></a><span class='ecrm-0500'>23</span><span class='ectt-0800'> </span><span id='textcolor2654'><span class='ectt-0800'>char</span></span><span class='ectt-0800'> *scratchpad;</span>
|
|
<a id='x1-61048r24'></a><span class='ecrm-0500'>24</span><span class='ectt-0800'> </span><span id='textcolor2655'><span class='ectt-0800'>char</span></span><span class='ectt-0800'> *ciphertext;</span>
|
|
<a id='x1-61050r25'></a><span class='ecrm-0500'>25</span><span class='ectt-0800'> </span><span id='textcolor2656'><span class='ectt-0800'>char</span></span><span class='ectt-0800'> *ivdata;</span>
|
|
<a id='x1-61052r26'></a><span class='ecrm-0500'>26</span><span class='ectt-0800'>};</span>
|
|
<a id='x1-61054r27'></a><span class='ecrm-0500'>27</span>
|
|
<a id='x1-61056r28'></a><span class='ecrm-0500'>28</span><span id='textcolor2657'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor2658'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> skcipher_def sk;</span>
|
|
<a id='x1-61058r29'></a><span class='ecrm-0500'>29</span>
|
|
<a id='x1-61060r30'></a><span class='ecrm-0500'>30</span><span id='textcolor2659'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor2660'><span class='ectt-0800'>void</span></span><span class='ectt-0800'> test_skcipher_finish(</span><span id='textcolor2661'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> skcipher_def *sk)</span>
|
|
<a id='x1-61062r31'></a><span class='ecrm-0500'>31</span><span class='ectt-0800'>{</span>
|
|
<a id='x1-61064r32'></a><span class='ecrm-0500'>32</span><span class='ectt-0800'> </span><span id='textcolor2662'><span class='ectt-0800'>if</span></span><span class='ectt-0800'> (sk->tfm)</span>
|
|
<a id='x1-61066r33'></a><span class='ecrm-0500'>33</span><span class='ectt-0800'> crypto_free_skcipher(sk->tfm);</span>
|
|
<a id='x1-61068r34'></a><span class='ecrm-0500'>34</span><span class='ectt-0800'> </span><span id='textcolor2663'><span class='ectt-0800'>if</span></span><span class='ectt-0800'> (sk->req)</span>
|
|
<a id='x1-61070r35'></a><span class='ecrm-0500'>35</span><span class='ectt-0800'> skcipher_request_free(sk->req);</span>
|
|
<a id='x1-61072r36'></a><span class='ecrm-0500'>36</span><span class='ectt-0800'> </span><span id='textcolor2664'><span class='ectt-0800'>if</span></span><span class='ectt-0800'> (sk->ivdata)</span>
|
|
<a id='x1-61074r37'></a><span class='ecrm-0500'>37</span><span class='ectt-0800'> kfree(sk->ivdata);</span>
|
|
<a id='x1-61076r38'></a><span class='ecrm-0500'>38</span><span class='ectt-0800'> </span><span id='textcolor2665'><span class='ectt-0800'>if</span></span><span class='ectt-0800'> (sk->scratchpad)</span>
|
|
<a id='x1-61078r39'></a><span class='ecrm-0500'>39</span><span class='ectt-0800'> kfree(sk->scratchpad);</span>
|
|
<a id='x1-61080r40'></a><span class='ecrm-0500'>40</span><span class='ectt-0800'> </span><span id='textcolor2666'><span class='ectt-0800'>if</span></span><span class='ectt-0800'> (sk->ciphertext)</span>
|
|
<a id='x1-61082r41'></a><span class='ecrm-0500'>41</span><span class='ectt-0800'> kfree(sk->ciphertext);</span>
|
|
<a id='x1-61084r42'></a><span class='ecrm-0500'>42</span><span class='ectt-0800'>}</span>
|
|
<a id='x1-61086r43'></a><span class='ecrm-0500'>43</span>
|
|
<a id='x1-61088r44'></a><span class='ecrm-0500'>44</span><span id='textcolor2667'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor2668'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> test_skcipher_result(</span><span id='textcolor2669'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> skcipher_def *sk, </span><span id='textcolor2670'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> rc)</span>
|
|
<a id='x1-61090r45'></a><span class='ecrm-0500'>45</span><span class='ectt-0800'>{</span>
|
|
<a id='x1-61092r46'></a><span class='ecrm-0500'>46</span><span class='ectt-0800'> </span><span id='textcolor2671'><span class='ectt-0800'>switch</span></span><span class='ectt-0800'> (rc) {</span>
|
|
<a id='x1-61094r47'></a><span class='ecrm-0500'>47</span><span class='ectt-0800'> </span><span id='textcolor2672'><span class='ectt-0800'>case</span></span><span class='ectt-0800'> 0:</span>
|
|
<a id='x1-61096r48'></a><span class='ecrm-0500'>48</span><span class='ectt-0800'> </span><span id='textcolor2673'><span class='ectt-0800'>break</span></span><span class='ectt-0800'>;</span>
|
|
<a id='x1-61098r49'></a><span class='ecrm-0500'>49</span><span class='ectt-0800'> </span><span id='textcolor2674'><span class='ectt-0800'>case</span></span><span class='ectt-0800'> -EINPROGRESS || -EBUSY:</span>
|
|
<a id='x1-61100r50'></a><span class='ecrm-0500'>50</span><span class='ectt-0800'> rc = wait_for_completion_interruptible(&sk->result.completion);</span>
|
|
<a id='x1-61102r51'></a><span class='ecrm-0500'>51</span><span class='ectt-0800'> </span><span id='textcolor2675'><span class='ectt-0800'>if</span></span><span class='ectt-0800'> (!rc && !sk->result.err) {</span>
|
|
<a id='x1-61104r52'></a><span class='ecrm-0500'>52</span><span class='ectt-0800'> reinit_completion(&sk->result.completion);</span>
|
|
<a id='x1-61106r53'></a><span class='ecrm-0500'>53</span><span class='ectt-0800'> </span><span id='textcolor2676'><span class='ectt-0800'>break</span></span><span class='ectt-0800'>;</span>
|
|
<a id='x1-61108r54'></a><span class='ecrm-0500'>54</span><span class='ectt-0800'> }</span>
|
|
<a id='x1-61110r55'></a><span class='ecrm-0500'>55</span><span class='ectt-0800'> pr_info(</span><span id='textcolor2677'><span class='ectt-0800'>"skcipher encrypt returned with %d result %d</span></span><span id='textcolor2678'><span class='ectt-0800'>\n</span></span><span id='textcolor2679'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>, rc,</span>
|
|
<a id='x1-61112r56'></a><span class='ecrm-0500'>56</span><span class='ectt-0800'> sk->result.err);</span>
|
|
<a id='x1-61114r57'></a><span class='ecrm-0500'>57</span><span class='ectt-0800'> </span><span id='textcolor2680'><span class='ectt-0800'>break</span></span><span class='ectt-0800'>;</span>
|
|
<a id='x1-61116r58'></a><span class='ecrm-0500'>58</span><span class='ectt-0800'> </span><span id='textcolor2681'><span class='ectt-0800'>default</span></span><span class='ectt-0800'>:</span>
|
|
<a id='x1-61118r59'></a><span class='ecrm-0500'>59</span><span class='ectt-0800'> pr_info(</span><span id='textcolor2682'><span class='ectt-0800'>"skcipher encrypt returned with %d result %d</span></span><span id='textcolor2683'><span class='ectt-0800'>\n</span></span><span id='textcolor2684'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>, rc,</span>
|
|
<a id='x1-61120r60'></a><span class='ecrm-0500'>60</span><span class='ectt-0800'> sk->result.err);</span>
|
|
<a id='x1-61122r61'></a><span class='ecrm-0500'>61</span><span class='ectt-0800'> </span><span id='textcolor2685'><span class='ectt-0800'>break</span></span><span class='ectt-0800'>;</span>
|
|
<a id='x1-61124r62'></a><span class='ecrm-0500'>62</span><span class='ectt-0800'> }</span>
|
|
<a id='x1-61126r63'></a><span class='ecrm-0500'>63</span>
|
|
<a id='x1-61128r64'></a><span class='ecrm-0500'>64</span><span class='ectt-0800'> init_completion(&sk->result.completion);</span>
|
|
<a id='x1-61130r65'></a><span class='ecrm-0500'>65</span>
|
|
<a id='x1-61132r66'></a><span class='ecrm-0500'>66</span><span class='ectt-0800'> </span><span id='textcolor2686'><span class='ectt-0800'>return</span></span><span class='ectt-0800'> rc;</span>
|
|
<a id='x1-61134r67'></a><span class='ecrm-0500'>67</span><span class='ectt-0800'>}</span>
|
|
<a id='x1-61136r68'></a><span class='ecrm-0500'>68</span>
|
|
<a id='x1-61138r69'></a><span class='ecrm-0500'>69</span><span id='textcolor2687'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor2688'><span class='ectt-0800'>void</span></span><span class='ectt-0800'> test_skcipher_callback(</span><span id='textcolor2689'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> crypto_async_request *req, </span><span id='textcolor2690'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> error)</span>
|
|
<a id='x1-61140r70'></a><span class='ecrm-0500'>70</span><span class='ectt-0800'>{</span>
|
|
<a id='x1-61142r71'></a><span class='ecrm-0500'>71</span><span class='ectt-0800'> </span><span id='textcolor2691'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> tcrypt_result *result = req->data;</span>
|
|
<a id='x1-61144r72'></a><span class='ecrm-0500'>72</span>
|
|
<a id='x1-61146r73'></a><span class='ecrm-0500'>73</span><span class='ectt-0800'> </span><span id='textcolor2692'><span class='ectt-0800'>if</span></span><span class='ectt-0800'> (error == -EINPROGRESS)</span>
|
|
<a id='x1-61148r74'></a><span class='ecrm-0500'>74</span><span class='ectt-0800'> </span><span id='textcolor2693'><span class='ectt-0800'>return</span></span><span class='ectt-0800'>;</span>
|
|
<a id='x1-61150r75'></a><span class='ecrm-0500'>75</span>
|
|
<a id='x1-61152r76'></a><span class='ecrm-0500'>76</span><span class='ectt-0800'> result->err = error;</span>
|
|
<a id='x1-61154r77'></a><span class='ecrm-0500'>77</span><span class='ectt-0800'> complete(&result->completion);</span>
|
|
<a id='x1-61156r78'></a><span class='ecrm-0500'>78</span><span class='ectt-0800'> pr_info(</span><span id='textcolor2694'><span class='ectt-0800'>"Encryption finished successfully</span></span><span id='textcolor2695'><span class='ectt-0800'>\n</span></span><span id='textcolor2696'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>);</span>
|
|
<a id='x1-61158r79'></a><span class='ecrm-0500'>79</span>
|
|
<a id='x1-61160r80'></a><span class='ecrm-0500'>80</span><span class='ectt-0800'> </span><span id='textcolor2697'><span class='ectt-0800'>/* decrypt data */</span></span>
|
|
<a id='x1-61162r81'></a><span class='ecrm-0500'>81</span><span id='textcolor2698'><span class='ectt-0800'>#if 0</span></span>
|
|
<a id='x1-61164r82'></a><span class='ecrm-0500'>82</span><span id='textcolor2699'><span class='ectt-0800'> memset((void*)sk.scratchpad, </span><span class='tctt-0800'>'</span><span class='ectt-0800'>-</span><span class='tctt-0800'>'</span><span class='ectt-0800'>, CIPHER_BLOCK_SIZE);</span></span>
|
|
<a id='x1-61166r83'></a><span class='ecrm-0500'>83</span><span id='textcolor2700'><span class='ectt-0800'> ret = crypto_skcipher_decrypt(sk.req);</span></span>
|
|
<a id='x1-61168r84'></a><span class='ecrm-0500'>84</span><span id='textcolor2701'><span class='ectt-0800'> ret = test_skcipher_result(&sk, ret);</span></span>
|
|
<a id='x1-61170r85'></a><span class='ecrm-0500'>85</span><span id='textcolor2702'><span class='ectt-0800'> if (ret)</span></span>
|
|
<a id='x1-61172r86'></a><span class='ecrm-0500'>86</span><span id='textcolor2703'><span class='ectt-0800'> return;</span></span>
|
|
<a id='x1-61174r87'></a><span class='ecrm-0500'>87</span>
|
|
<a id='x1-61176r88'></a><span class='ecrm-0500'>88</span><span id='textcolor2704'><span class='ectt-0800'> sg_copy_from_buffer(&sk.sg, 1, sk.scratchpad, CIPHER_BLOCK_SIZE);</span></span>
|
|
<a id='x1-61178r89'></a><span class='ecrm-0500'>89</span><span id='textcolor2705'><span class='ectt-0800'> sk.scratchpad[CIPHER_BLOCK_SIZE-1] = 0;</span></span>
|
|
<a id='x1-61180r90'></a><span class='ecrm-0500'>90</span>
|
|
<a id='x1-61182r91'></a><span class='ecrm-0500'>91</span><span id='textcolor2706'><span class='ectt-0800'> pr_info("Decryption request successful\n");</span></span>
|
|
<a id='x1-61184r92'></a><span class='ecrm-0500'>92</span><span id='textcolor2707'><span class='ectt-0800'> pr_info("Decrypted: %s\n", sk.scratchpad);</span></span>
|
|
<a id='x1-61186r93'></a><span class='ecrm-0500'>93</span><span id='textcolor2708'><span class='ectt-0800'>#endif</span></span>
|
|
<a id='x1-61188r94'></a><span class='ecrm-0500'>94</span><span class='ectt-0800'>}</span>
|
|
<a id='x1-61190r95'></a><span class='ecrm-0500'>95</span>
|
|
<a id='x1-61192r96'></a><span class='ecrm-0500'>96</span><span id='textcolor2709'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor2710'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> test_skcipher_encrypt(</span><span id='textcolor2711'><span class='ectt-0800'>char</span></span><span class='ectt-0800'> *plaintext, </span><span id='textcolor2712'><span class='ectt-0800'>char</span></span><span class='ectt-0800'> *password,</span>
|
|
<a id='x1-61194r97'></a><span class='ecrm-0500'>97</span><span class='ectt-0800'> </span><span id='textcolor2713'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> skcipher_def *sk)</span>
|
|
<a id='x1-61196r98'></a><span class='ecrm-0500'>98</span><span class='ectt-0800'>{</span>
|
|
<a id='x1-61198r99'></a><span class='ecrm-0500'>99</span><span class='ectt-0800'> </span><span id='textcolor2714'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> ret = -EFAULT;</span>
|
|
<a id='x1-61200r100'></a><span class='ecrm-0500'>100</span><span class='ectt-0800'> </span><span id='textcolor2715'><span class='ectt-0800'>unsigned</span></span><span class='ectt-0800'> </span><span id='textcolor2716'><span class='ectt-0800'>char</span></span><span class='ectt-0800'> key[SYMMETRIC_KEY_LENGTH];</span>
|
|
<a id='x1-61202r101'></a><span class='ecrm-0500'>101</span>
|
|
<a id='x1-61204r102'></a><span class='ecrm-0500'>102</span><span class='ectt-0800'> </span><span id='textcolor2717'><span class='ectt-0800'>if</span></span><span class='ectt-0800'> (!sk->tfm) {</span>
|
|
<a id='x1-61206r103'></a><span class='ecrm-0500'>103</span><span class='ectt-0800'> sk->tfm = crypto_alloc_skcipher(</span><span id='textcolor2718'><span class='ectt-0800'>"cbc-aes-aesni"</span></span><span class='ectt-0800'>, 0, 0);</span>
|
|
<a id='x1-61208r104'></a><span class='ecrm-0500'>104</span><span class='ectt-0800'> </span><span id='textcolor2719'><span class='ectt-0800'>if</span></span><span class='ectt-0800'> (IS_ERR(sk->tfm)) {</span>
|
|
<a id='x1-61210r105'></a><span class='ecrm-0500'>105</span><span class='ectt-0800'> pr_info(</span><span id='textcolor2720'><span class='ectt-0800'>"could not allocate skcipher handle</span></span><span id='textcolor2721'><span class='ectt-0800'>\n</span></span><span id='textcolor2722'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>);</span>
|
|
<a id='x1-61212r106'></a><span class='ecrm-0500'>106</span><span class='ectt-0800'> </span><span id='textcolor2723'><span class='ectt-0800'>return</span></span><span class='ectt-0800'> PTR_ERR(sk->tfm);</span>
|
|
<a id='x1-61214r107'></a><span class='ecrm-0500'>107</span><span class='ectt-0800'> }</span>
|
|
<a id='x1-61216r108'></a><span class='ecrm-0500'>108</span><span class='ectt-0800'> }</span>
|
|
<a id='x1-61218r109'></a><span class='ecrm-0500'>109</span>
|
|
<a id='x1-61220r110'></a><span class='ecrm-0500'>110</span><span class='ectt-0800'> </span><span id='textcolor2724'><span class='ectt-0800'>if</span></span><span class='ectt-0800'> (!sk->req) {</span>
|
|
<a id='x1-61222r111'></a><span class='ecrm-0500'>111</span><span class='ectt-0800'> sk->req = skcipher_request_alloc(sk->tfm, GFP_KERNEL);</span>
|
|
<a id='x1-61224r112'></a><span class='ecrm-0500'>112</span><span class='ectt-0800'> </span><span id='textcolor2725'><span class='ectt-0800'>if</span></span><span class='ectt-0800'> (!sk->req) {</span>
|
|
<a id='x1-61226r113'></a><span class='ecrm-0500'>113</span><span class='ectt-0800'> pr_info(</span><span id='textcolor2726'><span class='ectt-0800'>"could not allocate skcipher request</span></span><span id='textcolor2727'><span class='ectt-0800'>\n</span></span><span id='textcolor2728'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>);</span>
|
|
<a id='x1-61228r114'></a><span class='ecrm-0500'>114</span><span class='ectt-0800'> ret = -ENOMEM;</span>
|
|
<a id='x1-61230r115'></a><span class='ecrm-0500'>115</span><span class='ectt-0800'> </span><span id='textcolor2729'><span class='ectt-0800'>goto</span></span><span class='ectt-0800'> out;</span>
|
|
<a id='x1-61232r116'></a><span class='ecrm-0500'>116</span><span class='ectt-0800'> }</span>
|
|
<a id='x1-61234r117'></a><span class='ecrm-0500'>117</span><span class='ectt-0800'> }</span>
|
|
<a id='x1-61236r118'></a><span class='ecrm-0500'>118</span>
|
|
<a id='x1-61238r119'></a><span class='ecrm-0500'>119</span><span class='ectt-0800'> skcipher_request_set_callback(sk->req, CRYPTO_TFM_REQ_MAY_BACKLOG,</span>
|
|
<a id='x1-61240r120'></a><span class='ecrm-0500'>120</span><span class='ectt-0800'> test_skcipher_callback, &sk->result);</span>
|
|
<a id='x1-61242r121'></a><span class='ecrm-0500'>121</span>
|
|
<a id='x1-61244r122'></a><span class='ecrm-0500'>122</span><span class='ectt-0800'> </span><span id='textcolor2730'><span class='ectt-0800'>/* clear the key */</span></span>
|
|
<a id='x1-61246r123'></a><span class='ecrm-0500'>123</span><span class='ectt-0800'> memset((</span><span id='textcolor2731'><span class='ectt-0800'>void</span></span><span class='ectt-0800'> *)key, </span><span id='textcolor2732'><span class='tctt-0800'>'</span><span class='ectt-0800'>\0</span><span class='tctt-0800'>'</span></span><span class='ectt-0800'>, SYMMETRIC_KEY_LENGTH);</span>
|
|
<a id='x1-61248r124'></a><span class='ecrm-0500'>124</span>
|
|
<a id='x1-61250r125'></a><span class='ecrm-0500'>125</span><span class='ectt-0800'> </span><span id='textcolor2733'><span class='ectt-0800'>/* Use the world</span><span class='tctt-0800'>'</span><span class='ectt-0800'>s favourite password */</span></span>
|
|
<a id='x1-61252r126'></a><span class='ecrm-0500'>126</span><span class='ectt-0800'> sprintf((</span><span id='textcolor2734'><span class='ectt-0800'>char</span></span><span class='ectt-0800'> *)key, </span><span id='textcolor2735'><span class='ectt-0800'>"%s"</span></span><span class='ectt-0800'>, password);</span>
|
|
<a id='x1-61254r127'></a><span class='ecrm-0500'>127</span>
|
|
<a id='x1-61256r128'></a><span class='ecrm-0500'>128</span><span class='ectt-0800'> </span><span id='textcolor2736'><span class='ectt-0800'>/* AES 256 with given symmetric key */</span></span>
|
|
<a id='x1-61258r129'></a><span class='ecrm-0500'>129</span><span class='ectt-0800'> </span><span id='textcolor2737'><span class='ectt-0800'>if</span></span><span class='ectt-0800'> (crypto_skcipher_setkey(sk->tfm, key, SYMMETRIC_KEY_LENGTH)) {</span>
|
|
<a id='x1-61260r130'></a><span class='ecrm-0500'>130</span><span class='ectt-0800'> pr_info(</span><span id='textcolor2738'><span class='ectt-0800'>"key could not be set</span></span><span id='textcolor2739'><span class='ectt-0800'>\n</span></span><span id='textcolor2740'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>);</span>
|
|
<a id='x1-61262r131'></a><span class='ecrm-0500'>131</span><span class='ectt-0800'> ret = -EAGAIN;</span>
|
|
<a id='x1-61264r132'></a><span class='ecrm-0500'>132</span><span class='ectt-0800'> </span><span id='textcolor2741'><span class='ectt-0800'>goto</span></span><span class='ectt-0800'> out;</span>
|
|
<a id='x1-61266r133'></a><span class='ecrm-0500'>133</span><span class='ectt-0800'> }</span>
|
|
<a id='x1-61268r134'></a><span class='ecrm-0500'>134</span><span class='ectt-0800'> pr_info(</span><span id='textcolor2742'><span class='ectt-0800'>"Symmetric key: %s</span></span><span id='textcolor2743'><span class='ectt-0800'>\n</span></span><span id='textcolor2744'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>, key);</span>
|
|
<a id='x1-61270r135'></a><span class='ecrm-0500'>135</span><span class='ectt-0800'> pr_info(</span><span id='textcolor2745'><span class='ectt-0800'>"Plaintext: %s</span></span><span id='textcolor2746'><span class='ectt-0800'>\n</span></span><span id='textcolor2747'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>, plaintext);</span>
|
|
<a id='x1-61272r136'></a><span class='ecrm-0500'>136</span>
|
|
<a id='x1-61274r137'></a><span class='ecrm-0500'>137</span><span class='ectt-0800'> </span><span id='textcolor2748'><span class='ectt-0800'>if</span></span><span class='ectt-0800'> (!sk->ivdata) {</span>
|
|
<a id='x1-61276r138'></a><span class='ecrm-0500'>138</span><span class='ectt-0800'> </span><span id='textcolor2749'><span class='ectt-0800'>/* see https://en.wikipedia.org/wiki/Initialization_vector */</span></span>
|
|
<a id='x1-61278r139'></a><span class='ecrm-0500'>139</span><span class='ectt-0800'> sk->ivdata = kmalloc(CIPHER_BLOCK_SIZE, GFP_KERNEL);</span>
|
|
<a id='x1-61280r140'></a><span class='ecrm-0500'>140</span><span class='ectt-0800'> </span><span id='textcolor2750'><span class='ectt-0800'>if</span></span><span class='ectt-0800'> (!sk->ivdata) {</span>
|
|
<a id='x1-61282r141'></a><span class='ecrm-0500'>141</span><span class='ectt-0800'> pr_info(</span><span id='textcolor2751'><span class='ectt-0800'>"could not allocate ivdata</span></span><span id='textcolor2752'><span class='ectt-0800'>\n</span></span><span id='textcolor2753'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>);</span>
|
|
<a id='x1-61284r142'></a><span class='ecrm-0500'>142</span><span class='ectt-0800'> </span><span id='textcolor2754'><span class='ectt-0800'>goto</span></span><span class='ectt-0800'> out;</span>
|
|
<a id='x1-61286r143'></a><span class='ecrm-0500'>143</span><span class='ectt-0800'> }</span>
|
|
<a id='x1-61288r144'></a><span class='ecrm-0500'>144</span><span class='ectt-0800'> get_random_bytes(sk->ivdata, CIPHER_BLOCK_SIZE);</span>
|
|
<a id='x1-61290r145'></a><span class='ecrm-0500'>145</span><span class='ectt-0800'> }</span>
|
|
<a id='x1-61292r146'></a><span class='ecrm-0500'>146</span>
|
|
<a id='x1-61294r147'></a><span class='ecrm-0500'>147</span><span class='ectt-0800'> </span><span id='textcolor2755'><span class='ectt-0800'>if</span></span><span class='ectt-0800'> (!sk->scratchpad) {</span>
|
|
<a id='x1-61296r148'></a><span class='ecrm-0500'>148</span><span class='ectt-0800'> </span><span id='textcolor2756'><span class='ectt-0800'>/* The text to be encrypted */</span></span>
|
|
<a id='x1-61298r149'></a><span class='ecrm-0500'>149</span><span class='ectt-0800'> sk->scratchpad = kmalloc(CIPHER_BLOCK_SIZE, GFP_KERNEL);</span>
|
|
<a id='x1-61300r150'></a><span class='ecrm-0500'>150</span><span class='ectt-0800'> </span><span id='textcolor2757'><span class='ectt-0800'>if</span></span><span class='ectt-0800'> (!sk->scratchpad) {</span>
|
|
<a id='x1-61302r151'></a><span class='ecrm-0500'>151</span><span class='ectt-0800'> pr_info(</span><span id='textcolor2758'><span class='ectt-0800'>"could not allocate scratchpad</span></span><span id='textcolor2759'><span class='ectt-0800'>\n</span></span><span id='textcolor2760'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>);</span>
|
|
<a id='x1-61304r152'></a><span class='ecrm-0500'>152</span><span class='ectt-0800'> </span><span id='textcolor2761'><span class='ectt-0800'>goto</span></span><span class='ectt-0800'> out;</span>
|
|
<a id='x1-61306r153'></a><span class='ecrm-0500'>153</span><span class='ectt-0800'> }</span>
|
|
<a id='x1-61308r154'></a><span class='ecrm-0500'>154</span><span class='ectt-0800'> }</span>
|
|
<a id='x1-61310r155'></a><span class='ecrm-0500'>155</span><span class='ectt-0800'> sprintf((</span><span id='textcolor2762'><span class='ectt-0800'>char</span></span><span class='ectt-0800'> *)sk->scratchpad, </span><span id='textcolor2763'><span class='ectt-0800'>"%s"</span></span><span class='ectt-0800'>, plaintext);</span>
|
|
<a id='x1-61312r156'></a><span class='ecrm-0500'>156</span>
|
|
<a id='x1-61314r157'></a><span class='ecrm-0500'>157</span><span class='ectt-0800'> sg_init_one(&sk->sg, sk->scratchpad, CIPHER_BLOCK_SIZE);</span>
|
|
<a id='x1-61316r158'></a><span class='ecrm-0500'>158</span><span class='ectt-0800'> skcipher_request_set_crypt(sk->req, &sk->sg, &sk->sg, CIPHER_BLOCK_SIZE,</span>
|
|
<a id='x1-61318r159'></a><span class='ecrm-0500'>159</span><span class='ectt-0800'> sk->ivdata);</span>
|
|
<a id='x1-61320r160'></a><span class='ecrm-0500'>160</span><span class='ectt-0800'> init_completion(&sk->result.completion);</span>
|
|
<a id='x1-61322r161'></a><span class='ecrm-0500'>161</span>
|
|
<a id='x1-61324r162'></a><span class='ecrm-0500'>162</span><span class='ectt-0800'> </span><span id='textcolor2764'><span class='ectt-0800'>/* encrypt data */</span></span>
|
|
<a id='x1-61326r163'></a><span class='ecrm-0500'>163</span><span class='ectt-0800'> ret = crypto_skcipher_encrypt(sk->req);</span>
|
|
<a id='x1-61328r164'></a><span class='ecrm-0500'>164</span><span class='ectt-0800'> ret = test_skcipher_result(sk, ret);</span>
|
|
<a id='x1-61330r165'></a><span class='ecrm-0500'>165</span><span class='ectt-0800'> </span><span id='textcolor2765'><span class='ectt-0800'>if</span></span><span class='ectt-0800'> (ret)</span>
|
|
<a id='x1-61332r166'></a><span class='ecrm-0500'>166</span><span class='ectt-0800'> </span><span id='textcolor2766'><span class='ectt-0800'>goto</span></span><span class='ectt-0800'> out;</span>
|
|
<a id='x1-61334r167'></a><span class='ecrm-0500'>167</span>
|
|
<a id='x1-61336r168'></a><span class='ecrm-0500'>168</span><span class='ectt-0800'> pr_info(</span><span id='textcolor2767'><span class='ectt-0800'>"Encryption request successful</span></span><span id='textcolor2768'><span class='ectt-0800'>\n</span></span><span id='textcolor2769'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>);</span>
|
|
<a id='x1-61338r169'></a><span class='ecrm-0500'>169</span>
|
|
<a id='x1-61340r170'></a><span class='ecrm-0500'>170</span><span class='ectt-0800'>out:</span>
|
|
<a id='x1-61342r171'></a><span class='ecrm-0500'>171</span><span class='ectt-0800'> </span><span id='textcolor2770'><span class='ectt-0800'>return</span></span><span class='ectt-0800'> ret;</span>
|
|
<a id='x1-61344r172'></a><span class='ecrm-0500'>172</span><span class='ectt-0800'>}</span>
|
|
<a id='x1-61346r173'></a><span class='ecrm-0500'>173</span>
|
|
<a id='x1-61348r174'></a><span class='ecrm-0500'>174</span><span id='textcolor2771'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor2772'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> cryptoapi_init(</span><span id='textcolor2773'><span class='ectt-0800'>void</span></span><span class='ectt-0800'>)</span>
|
|
<a id='x1-61350r175'></a><span class='ecrm-0500'>175</span><span class='ectt-0800'>{</span>
|
|
<a id='x1-61352r176'></a><span class='ecrm-0500'>176</span><span class='ectt-0800'> </span><span id='textcolor2774'><span class='ectt-0800'>/* The world</span><span class='tctt-0800'>'</span><span class='ectt-0800'>s favorite password */</span></span>
|
|
<a id='x1-61354r177'></a><span class='ecrm-0500'>177</span><span class='ectt-0800'> </span><span id='textcolor2775'><span class='ectt-0800'>char</span></span><span class='ectt-0800'> *password = </span><span id='textcolor2776'><span class='ectt-0800'>"password123"</span></span><span class='ectt-0800'>;</span>
|
|
<a id='x1-61356r178'></a><span class='ecrm-0500'>178</span>
|
|
<a id='x1-61358r179'></a><span class='ecrm-0500'>179</span><span class='ectt-0800'> sk.tfm = NULL;</span>
|
|
<a id='x1-61360r180'></a><span class='ecrm-0500'>180</span><span class='ectt-0800'> sk.req = NULL;</span>
|
|
<a id='x1-61362r181'></a><span class='ecrm-0500'>181</span><span class='ectt-0800'> sk.scratchpad = NULL;</span>
|
|
<a id='x1-61364r182'></a><span class='ecrm-0500'>182</span><span class='ectt-0800'> sk.ciphertext = NULL;</span>
|
|
<a id='x1-61366r183'></a><span class='ecrm-0500'>183</span><span class='ectt-0800'> sk.ivdata = NULL;</span>
|
|
<a id='x1-61368r184'></a><span class='ecrm-0500'>184</span>
|
|
<a id='x1-61370r185'></a><span class='ecrm-0500'>185</span><span class='ectt-0800'> test_skcipher_encrypt(</span><span id='textcolor2777'><span class='ectt-0800'>"Testing"</span></span><span class='ectt-0800'>, password, &sk);</span>
|
|
<a id='x1-61372r186'></a><span class='ecrm-0500'>186</span><span class='ectt-0800'> </span><span id='textcolor2778'><span class='ectt-0800'>return</span></span><span class='ectt-0800'> 0;</span>
|
|
<a id='x1-61374r187'></a><span class='ecrm-0500'>187</span><span class='ectt-0800'>}</span>
|
|
<a id='x1-61376r188'></a><span class='ecrm-0500'>188</span>
|
|
<a id='x1-61378r189'></a><span class='ecrm-0500'>189</span><span id='textcolor2779'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor2780'><span class='ectt-0800'>void</span></span><span class='ectt-0800'> cryptoapi_exit(</span><span id='textcolor2781'><span class='ectt-0800'>void</span></span><span class='ectt-0800'>)</span>
|
|
<a id='x1-61380r190'></a><span class='ecrm-0500'>190</span><span class='ectt-0800'>{</span>
|
|
<a id='x1-61382r191'></a><span class='ecrm-0500'>191</span><span class='ectt-0800'> test_skcipher_finish(&sk);</span>
|
|
<a id='x1-61384r192'></a><span class='ecrm-0500'>192</span><span class='ectt-0800'>}</span>
|
|
<a id='x1-61386r193'></a><span class='ecrm-0500'>193</span>
|
|
<a id='x1-61388r194'></a><span class='ecrm-0500'>194</span><span class='ectt-0800'>module_init(cryptoapi_init);</span>
|
|
<a id='x1-61390r195'></a><span class='ecrm-0500'>195</span><span class='ectt-0800'>module_exit(cryptoapi_exit);</span>
|
|
<a id='x1-61392r196'></a><span class='ecrm-0500'>196</span>
|
|
<a id='x1-61394r197'></a><span class='ecrm-0500'>197</span><span class='ectt-0800'>MODULE_DESCRIPTION(</span><span id='textcolor2782'><span class='ectt-0800'>"Symmetric key encryption example"</span></span><span class='ectt-0800'>);</span>
|
|
<a id='x1-61396r198'></a><span class='ecrm-0500'>198</span><span class='ectt-0800'>MODULE_LICENSE(</span><span id='textcolor2783'><span class='ectt-0800'>"GPL"</span></span><span class='ectt-0800'>);</span></pre>
|
|
<!-- l. 1702 --><p class='noindent'>
|
|
</p>
|
|
<h3 class='sectionHead' id='standardizing-the-interfaces-the-device-model'><span class='titlemark'>17 </span> <a id='x1-6200017'></a>Standardizing the interfaces: The Device Model</h3>
|
|
<!-- l. 1704 --><p class='noindent'>Up to this point we have seen all kinds of modules doing all kinds of things, but there
|
|
was no consistency in their interfaces with the rest of the kernel. To impose some
|
|
consistency such that there is at minimum a standardized way to start, suspend and
|
|
resume a device a device model was added. An example is shown below, and you can
|
|
use this as a template to add your own suspend, resume or other interface
|
|
functions.
|
|
</p><!-- l. 1 --><p class='indent'>
|
|
</p>
|
|
<pre class='fancyvrb' id='fancyvrb74'><a id='x1-62002r1'></a><span class='ecrm-0500'>1</span><span id='textcolor2784'><span class='ectt-0800'>/*</span></span>
|
|
<a id='x1-62004r2'></a><span class='ecrm-0500'>2</span><span id='textcolor2785'><span class='ectt-0800'> * devicemodel.c</span></span>
|
|
<a id='x1-62006r3'></a><span class='ecrm-0500'>3</span><span id='textcolor2786'><span class='ectt-0800'> */</span></span>
|
|
<a id='x1-62008r4'></a><span class='ecrm-0500'>4</span><span id='textcolor2787'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor2788'><span class='ectt-0800'><linux/kernel.h></span></span>
|
|
<a id='x1-62010r5'></a><span class='ecrm-0500'>5</span><span id='textcolor2789'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor2790'><span class='ectt-0800'><linux/module.h></span></span>
|
|
<a id='x1-62012r6'></a><span class='ecrm-0500'>6</span><span id='textcolor2791'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor2792'><span class='ectt-0800'><linux/platform_device.h></span></span>
|
|
<a id='x1-62014r7'></a><span class='ecrm-0500'>7</span>
|
|
<a id='x1-62016r8'></a><span class='ecrm-0500'>8</span><span id='textcolor2793'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> devicemodel_data {</span>
|
|
<a id='x1-62018r9'></a><span class='ecrm-0500'>9</span><span class='ectt-0800'> </span><span id='textcolor2794'><span class='ectt-0800'>char</span></span><span class='ectt-0800'> *greeting;</span>
|
|
<a id='x1-62020r10'></a><span class='ecrm-0500'>10</span><span class='ectt-0800'> </span><span id='textcolor2795'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> number;</span>
|
|
<a id='x1-62022r11'></a><span class='ecrm-0500'>11</span><span class='ectt-0800'>};</span>
|
|
<a id='x1-62024r12'></a><span class='ecrm-0500'>12</span>
|
|
<a id='x1-62026r13'></a><span class='ecrm-0500'>13</span><span id='textcolor2796'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor2797'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> devicemodel_probe(</span><span id='textcolor2798'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> platform_device *dev)</span>
|
|
<a id='x1-62028r14'></a><span class='ecrm-0500'>14</span><span class='ectt-0800'>{</span>
|
|
<a id='x1-62030r15'></a><span class='ecrm-0500'>15</span><span class='ectt-0800'> </span><span id='textcolor2799'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> devicemodel_data *pd =</span>
|
|
<a id='x1-62032r16'></a><span class='ecrm-0500'>16</span><span class='ectt-0800'> (</span><span id='textcolor2800'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> devicemodel_data *)(dev->dev.platform_data);</span>
|
|
<a id='x1-62034r17'></a><span class='ecrm-0500'>17</span>
|
|
<a id='x1-62036r18'></a><span class='ecrm-0500'>18</span><span class='ectt-0800'> pr_info(</span><span id='textcolor2801'><span class='ectt-0800'>"devicemodel probe</span></span><span id='textcolor2802'><span class='ectt-0800'>\n</span></span><span id='textcolor2803'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>);</span>
|
|
<a id='x1-62038r19'></a><span class='ecrm-0500'>19</span><span class='ectt-0800'> pr_info(</span><span id='textcolor2804'><span class='ectt-0800'>"devicemodel greeting: %s; %d</span></span><span id='textcolor2805'><span class='ectt-0800'>\n</span></span><span id='textcolor2806'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>, pd->greeting, pd->number);</span>
|
|
<a id='x1-62040r20'></a><span class='ecrm-0500'>20</span>
|
|
<a id='x1-62042r21'></a><span class='ecrm-0500'>21</span><span class='ectt-0800'> </span><span id='textcolor2807'><span class='ectt-0800'>/* Your device initialization code */</span></span>
|
|
<a id='x1-62044r22'></a><span class='ecrm-0500'>22</span>
|
|
<a id='x1-62046r23'></a><span class='ecrm-0500'>23</span><span class='ectt-0800'> </span><span id='textcolor2808'><span class='ectt-0800'>return</span></span><span class='ectt-0800'> 0;</span>
|
|
<a id='x1-62048r24'></a><span class='ecrm-0500'>24</span><span class='ectt-0800'>}</span>
|
|
<a id='x1-62050r25'></a><span class='ecrm-0500'>25</span>
|
|
<a id='x1-62052r26'></a><span class='ecrm-0500'>26</span><span id='textcolor2809'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor2810'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> devicemodel_remove(</span><span id='textcolor2811'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> platform_device *dev)</span>
|
|
<a id='x1-62054r27'></a><span class='ecrm-0500'>27</span><span class='ectt-0800'>{</span>
|
|
<a id='x1-62056r28'></a><span class='ecrm-0500'>28</span><span class='ectt-0800'> pr_info(</span><span id='textcolor2812'><span class='ectt-0800'>"devicemodel example removed</span></span><span id='textcolor2813'><span class='ectt-0800'>\n</span></span><span id='textcolor2814'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>);</span>
|
|
<a id='x1-62058r29'></a><span class='ecrm-0500'>29</span>
|
|
<a id='x1-62060r30'></a><span class='ecrm-0500'>30</span><span class='ectt-0800'> </span><span id='textcolor2815'><span class='ectt-0800'>/* Your device removal code */</span></span>
|
|
<a id='x1-62062r31'></a><span class='ecrm-0500'>31</span>
|
|
<a id='x1-62064r32'></a><span class='ecrm-0500'>32</span><span class='ectt-0800'> </span><span id='textcolor2816'><span class='ectt-0800'>return</span></span><span class='ectt-0800'> 0;</span>
|
|
<a id='x1-62066r33'></a><span class='ecrm-0500'>33</span><span class='ectt-0800'>}</span>
|
|
<a id='x1-62068r34'></a><span class='ecrm-0500'>34</span>
|
|
<a id='x1-62070r35'></a><span class='ecrm-0500'>35</span><span id='textcolor2817'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor2818'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> devicemodel_suspend(</span><span id='textcolor2819'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> device *dev)</span>
|
|
<a id='x1-62072r36'></a><span class='ecrm-0500'>36</span><span class='ectt-0800'>{</span>
|
|
<a id='x1-62074r37'></a><span class='ecrm-0500'>37</span><span class='ectt-0800'> pr_info(</span><span id='textcolor2820'><span class='ectt-0800'>"devicemodel example suspend</span></span><span id='textcolor2821'><span class='ectt-0800'>\n</span></span><span id='textcolor2822'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>);</span>
|
|
<a id='x1-62076r38'></a><span class='ecrm-0500'>38</span>
|
|
<a id='x1-62078r39'></a><span class='ecrm-0500'>39</span><span class='ectt-0800'> </span><span id='textcolor2823'><span class='ectt-0800'>/* Your device suspend code */</span></span>
|
|
<a id='x1-62080r40'></a><span class='ecrm-0500'>40</span>
|
|
<a id='x1-62082r41'></a><span class='ecrm-0500'>41</span><span class='ectt-0800'> </span><span id='textcolor2824'><span class='ectt-0800'>return</span></span><span class='ectt-0800'> 0;</span>
|
|
<a id='x1-62084r42'></a><span class='ecrm-0500'>42</span><span class='ectt-0800'>}</span>
|
|
<a id='x1-62086r43'></a><span class='ecrm-0500'>43</span>
|
|
<a id='x1-62088r44'></a><span class='ecrm-0500'>44</span><span id='textcolor2825'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor2826'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> devicemodel_resume(</span><span id='textcolor2827'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> device *dev)</span>
|
|
<a id='x1-62090r45'></a><span class='ecrm-0500'>45</span><span class='ectt-0800'>{</span>
|
|
<a id='x1-62092r46'></a><span class='ecrm-0500'>46</span><span class='ectt-0800'> pr_info(</span><span id='textcolor2828'><span class='ectt-0800'>"devicemodel example resume</span></span><span id='textcolor2829'><span class='ectt-0800'>\n</span></span><span id='textcolor2830'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>);</span>
|
|
<a id='x1-62094r47'></a><span class='ecrm-0500'>47</span>
|
|
<a id='x1-62096r48'></a><span class='ecrm-0500'>48</span><span class='ectt-0800'> </span><span id='textcolor2831'><span class='ectt-0800'>/* Your device resume code */</span></span>
|
|
<a id='x1-62098r49'></a><span class='ecrm-0500'>49</span>
|
|
<a id='x1-62100r50'></a><span class='ecrm-0500'>50</span><span class='ectt-0800'> </span><span id='textcolor2832'><span class='ectt-0800'>return</span></span><span class='ectt-0800'> 0;</span>
|
|
<a id='x1-62102r51'></a><span class='ecrm-0500'>51</span><span class='ectt-0800'>}</span>
|
|
<a id='x1-62104r52'></a><span class='ecrm-0500'>52</span>
|
|
<a id='x1-62106r53'></a><span class='ecrm-0500'>53</span><span id='textcolor2833'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor2834'><span class='ectt-0800'>const</span></span><span class='ectt-0800'> </span><span id='textcolor2835'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> dev_pm_ops devicemodel_pm_ops = {</span>
|
|
<a id='x1-62108r54'></a><span class='ecrm-0500'>54</span><span class='ectt-0800'> .suspend = devicemodel_suspend,</span>
|
|
<a id='x1-62110r55'></a><span class='ecrm-0500'>55</span><span class='ectt-0800'> .resume = devicemodel_resume,</span>
|
|
<a id='x1-62112r56'></a><span class='ecrm-0500'>56</span><span class='ectt-0800'> .poweroff = devicemodel_suspend,</span>
|
|
<a id='x1-62114r57'></a><span class='ecrm-0500'>57</span><span class='ectt-0800'> .freeze = devicemodel_suspend,</span>
|
|
<a id='x1-62116r58'></a><span class='ecrm-0500'>58</span><span class='ectt-0800'> .thaw = devicemodel_resume,</span>
|
|
<a id='x1-62118r59'></a><span class='ecrm-0500'>59</span><span class='ectt-0800'> .restore = devicemodel_resume,</span>
|
|
<a id='x1-62120r60'></a><span class='ecrm-0500'>60</span><span class='ectt-0800'>};</span>
|
|
<a id='x1-62122r61'></a><span class='ecrm-0500'>61</span>
|
|
<a id='x1-62124r62'></a><span class='ecrm-0500'>62</span><span id='textcolor2836'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor2837'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> platform_driver devicemodel_driver = {</span>
|
|
<a id='x1-62126r63'></a><span class='ecrm-0500'>63</span><span class='ectt-0800'> .driver =</span>
|
|
<a id='x1-62128r64'></a><span class='ecrm-0500'>64</span><span class='ectt-0800'> {</span>
|
|
<a id='x1-62130r65'></a><span class='ecrm-0500'>65</span><span class='ectt-0800'> .name = </span><span id='textcolor2838'><span class='ectt-0800'>"devicemodel_example"</span></span><span class='ectt-0800'>,</span>
|
|
<a id='x1-62132r66'></a><span class='ecrm-0500'>66</span><span class='ectt-0800'> .owner = THIS_MODULE,</span>
|
|
<a id='x1-62134r67'></a><span class='ecrm-0500'>67</span><span class='ectt-0800'> .pm = &devicemodel_pm_ops,</span>
|
|
<a id='x1-62136r68'></a><span class='ecrm-0500'>68</span><span class='ectt-0800'> },</span>
|
|
<a id='x1-62138r69'></a><span class='ecrm-0500'>69</span><span class='ectt-0800'> .probe = devicemodel_probe,</span>
|
|
<a id='x1-62140r70'></a><span class='ecrm-0500'>70</span><span class='ectt-0800'> .remove = devicemodel_remove,</span>
|
|
<a id='x1-62142r71'></a><span class='ecrm-0500'>71</span><span class='ectt-0800'>};</span>
|
|
<a id='x1-62144r72'></a><span class='ecrm-0500'>72</span>
|
|
<a id='x1-62146r73'></a><span class='ecrm-0500'>73</span><span id='textcolor2839'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor2840'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> devicemodel_init(</span><span id='textcolor2841'><span class='ectt-0800'>void</span></span><span class='ectt-0800'>)</span>
|
|
<a id='x1-62148r74'></a><span class='ecrm-0500'>74</span><span class='ectt-0800'>{</span>
|
|
<a id='x1-62150r75'></a><span class='ecrm-0500'>75</span><span class='ectt-0800'> </span><span id='textcolor2842'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> ret;</span>
|
|
<a id='x1-62152r76'></a><span class='ecrm-0500'>76</span>
|
|
<a id='x1-62154r77'></a><span class='ecrm-0500'>77</span><span class='ectt-0800'> pr_info(</span><span id='textcolor2843'><span class='ectt-0800'>"devicemodel init</span></span><span id='textcolor2844'><span class='ectt-0800'>\n</span></span><span id='textcolor2845'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>);</span>
|
|
<a id='x1-62156r78'></a><span class='ecrm-0500'>78</span>
|
|
<a id='x1-62158r79'></a><span class='ecrm-0500'>79</span><span class='ectt-0800'> ret = platform_driver_register(&devicemodel_driver);</span>
|
|
<a id='x1-62160r80'></a><span class='ecrm-0500'>80</span>
|
|
<a id='x1-62162r81'></a><span class='ecrm-0500'>81</span><span class='ectt-0800'> </span><span id='textcolor2846'><span class='ectt-0800'>if</span></span><span class='ectt-0800'> (ret) {</span>
|
|
<a id='x1-62164r82'></a><span class='ecrm-0500'>82</span><span class='ectt-0800'> pr_err(</span><span id='textcolor2847'><span class='ectt-0800'>"Unable to register driver</span></span><span id='textcolor2848'><span class='ectt-0800'>\n</span></span><span id='textcolor2849'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>);</span>
|
|
<a id='x1-62166r83'></a><span class='ecrm-0500'>83</span><span class='ectt-0800'> </span><span id='textcolor2850'><span class='ectt-0800'>return</span></span><span class='ectt-0800'> ret;</span>
|
|
<a id='x1-62168r84'></a><span class='ecrm-0500'>84</span><span class='ectt-0800'> }</span>
|
|
<a id='x1-62170r85'></a><span class='ecrm-0500'>85</span>
|
|
<a id='x1-62172r86'></a><span class='ecrm-0500'>86</span><span class='ectt-0800'> </span><span id='textcolor2851'><span class='ectt-0800'>return</span></span><span class='ectt-0800'> 0;</span>
|
|
<a id='x1-62174r87'></a><span class='ecrm-0500'>87</span><span class='ectt-0800'>}</span>
|
|
<a id='x1-62176r88'></a><span class='ecrm-0500'>88</span>
|
|
<a id='x1-62178r89'></a><span class='ecrm-0500'>89</span><span id='textcolor2852'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor2853'><span class='ectt-0800'>void</span></span><span class='ectt-0800'> devicemodel_exit(</span><span id='textcolor2854'><span class='ectt-0800'>void</span></span><span class='ectt-0800'>)</span>
|
|
<a id='x1-62180r90'></a><span class='ecrm-0500'>90</span><span class='ectt-0800'>{</span>
|
|
<a id='x1-62182r91'></a><span class='ecrm-0500'>91</span><span class='ectt-0800'> pr_info(</span><span id='textcolor2855'><span class='ectt-0800'>"devicemodel exit</span></span><span id='textcolor2856'><span class='ectt-0800'>\n</span></span><span id='textcolor2857'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>);</span>
|
|
<a id='x1-62184r92'></a><span class='ecrm-0500'>92</span><span class='ectt-0800'> platform_driver_unregister(&devicemodel_driver);</span>
|
|
<a id='x1-62186r93'></a><span class='ecrm-0500'>93</span><span class='ectt-0800'>}</span>
|
|
<a id='x1-62188r94'></a><span class='ecrm-0500'>94</span>
|
|
<a id='x1-62190r95'></a><span class='ecrm-0500'>95</span><span class='ectt-0800'>module_init(devicemodel_init);</span>
|
|
<a id='x1-62192r96'></a><span class='ecrm-0500'>96</span><span class='ectt-0800'>module_exit(devicemodel_exit);</span>
|
|
<a id='x1-62194r97'></a><span class='ecrm-0500'>97</span>
|
|
<a id='x1-62196r98'></a><span class='ecrm-0500'>98</span><span class='ectt-0800'>MODULE_LICENSE(</span><span id='textcolor2858'><span class='ectt-0800'>"GPL"</span></span><span class='ectt-0800'>);</span>
|
|
<a id='x1-62198r99'></a><span class='ecrm-0500'>99</span><span class='ectt-0800'>MODULE_DESCRIPTION(</span><span id='textcolor2859'><span class='ectt-0800'>"Linux Device Model example"</span></span><span class='ectt-0800'>);</span></pre>
|
|
<!-- l. 1710 --><p class='noindent'>
|
|
</p>
|
|
<h3 class='sectionHead' id='optimizations'><span class='titlemark'>18 </span> <a id='x1-6300018'></a>Optimizations</h3>
|
|
<!-- l. 1712 --><p class='noindent'>
|
|
</p>
|
|
<h4 class='subsectionHead' id='likely-and-unlikely-conditions'><span class='titlemark'>18.1 </span> <a id='x1-6400018.1'></a>Likely and Unlikely conditions</h4>
|
|
<!-- l. 1714 --><p class='noindent'>Sometimes you might want your code to run as quickly as possible,
|
|
especially if it is handling an interrupt or doing something which might
|
|
cause noticeable latency. If your code contains boolean conditions and if
|
|
you know that the conditions are almost always likely to evaluate as either
|
|
<code> <span class='ectt-1000'>true</span>
|
|
</code> or <code> <span class='ectt-1000'>false</span>
|
|
</code>, then you can allow the compiler to optimize for this using the
|
|
<code> <span class='ectt-1000'>likely</span>
|
|
</code> and <code> <span class='ectt-1000'>unlikely</span>
|
|
</code> macros. For example, when allocating memory you are almost always expecting this
|
|
to succeed.
|
|
</p><!-- l. 1 --><p class='indent'>
|
|
</p>
|
|
<pre class='fancyvrb' id='fancyvrb75'><a id='x1-64012r1'></a><span class='ecrm-0500'>1</span><span class='ectt-0800'>bvl = bvec_alloc(gfp_mask, nr_iovecs, &idx);</span>
|
|
<a id='x1-64014r2'></a><span class='ecrm-0500'>2</span><span id='textcolor2860'><span class='ectt-0800'>if</span></span><span class='ectt-0800'> (unlikely(!bvl)) {</span>
|
|
<a id='x1-64016r3'></a><span class='ecrm-0500'>3</span><span class='ectt-0800'> mempool_free(bio, bio_pool);</span>
|
|
<a id='x1-64018r4'></a><span class='ecrm-0500'>4</span><span class='ectt-0800'> bio = NULL;</span>
|
|
<a id='x1-64020r5'></a><span class='ecrm-0500'>5</span><span class='ectt-0800'> </span><span id='textcolor2861'><span class='ectt-0800'>goto</span></span><span class='ectt-0800'> out;</span>
|
|
<a id='x1-64022r6'></a><span class='ecrm-0500'>6</span><span class='ectt-0800'>}</span></pre>
|
|
|
|
|
|
|
|
<!-- l. 1728 --><p class='indent'> When the <code> <span class='ectt-1000'>unlikely</span>
|
|
</code> macro is used, the compiler alters its machine instruction output, so that it
|
|
continues along the false branch and only jumps if the condition is true. That
|
|
avoids flushing the processor pipeline. The opposite happens if you use the
|
|
<code> <span class='ectt-1000'>likely</span>
|
|
</code> macro.
|
|
</p><!-- l. 1732 --><p class='noindent'>
|
|
</p>
|
|
<h3 class='sectionHead' id='common-pitfalls'><span class='titlemark'>19 </span> <a id='x1-6500019'></a>Common Pitfalls</h3>
|
|
<!-- l. 1735 --><p class='noindent'>
|
|
</p>
|
|
<h4 class='subsectionHead' id='using-standard-libraries'><span class='titlemark'>19.1 </span> <a id='x1-6600019.1'></a>Using standard libraries</h4>
|
|
<!-- l. 1737 --><p class='noindent'>You can not do that. In a kernel module, you can only use kernel functions which are
|
|
the functions you can see in <span class='obeylines-h'><span class='verb'><span class='ectt-1000'>/proc/kallsyms</span></span></span>.
|
|
</p><!-- l. 1740 --><p class='noindent'>
|
|
</p>
|
|
<h4 class='subsectionHead' id='disabling-interrupts'><span class='titlemark'>19.2 </span> <a id='x1-6700019.2'></a>Disabling interrupts</h4>
|
|
<!-- l. 1742 --><p class='noindent'>You might need to do this for a short time and that is OK, but if you do not enable
|
|
them afterwards, your system will be stuck and you will have to power it
|
|
off.
|
|
</p><!-- l. 1744 --><p class='noindent'>
|
|
</p>
|
|
<h3 class='sectionHead' id='where-to-go-from-here'><span class='titlemark'>20 </span> <a id='x1-6800020'></a>Where To Go From Here?</h3>
|
|
<!-- l. 1746 --><p class='noindent'>For people seriously interested in kernel programming, I recommend <a href='https://kernelnewbies.org'>kernelnewbies.org</a>
|
|
and the <a href='https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/tree/Documentation'>Documentation</a> subdirectory within the kernel source code which is not
|
|
always easy to understand but can be a starting point for further investigation. Also,
|
|
as Linus Torvalds said, the best way to learn the kernel is to read the source code
|
|
yourself.
|
|
</p><!-- l. 1749 --><p class='indent'> If you are interested in more examples of short kernel modules then searching on
|
|
sites such as Github and Gitlab is a good way to start, although there is a lot of
|
|
duplication of older LKMPG examples which may not compile with newer kernel
|
|
versions. You will also be able to find examples of the use of kernel modules to attack
|
|
or compromise systems or exfiltrate data and those can be useful for thinking about
|
|
how to defend systems and learning about existing security mechanisms within the
|
|
kernel.
|
|
|
|
|
|
|
|
</p><!-- l. 1752 --><p class='indent'> I hope I have helped you in your quest to become a better programmer, or at
|
|
least to have fun through technology. And, if you do write useful kernel modules, I
|
|
hope you publish them under the GPL, so I can use them too.
|
|
</p><!-- l. 1755 --><p class='indent'> If you would like to contribute to this guide or notice anything glaringly wrong,
|
|
please create an issue at <a class='url' href='https://github.com/sysprog21/lkmpg'><span class='ectt-1000'>https://github.com/sysprog21/lkmpg</span></a>.
|
|
</p><!-- l. 1757 --><p class='indent'> Happy hacking!
|
|
</p>
|
|
<div class='footnotes'><!-- l. 1586 --><p class='indent'> <span class='footnote-mark'><a href='#fn1x0-bk' id='fn1x0'><sup class='textsuperscript'>1</sup></a></span><span class='ecrm-0800'>The goal of threaded interrupts is to push more of the work to separate threads, so that the
|
|
</span><span class='ecrm-0800'>minimum needed for acknowledging an interrupt is reduced, and therefore the time spent handling
|
|
</span><span class='ecrm-0800'>the interrupt (where it can’t handle any other interrupts at the same time) is reduced. See
|
|
</span><span class='ecrm-0800'>https://lwn.net/Articles/302043/</span></p> </div>
|
|
|
|
</body>
|
|
</html> |