⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 kernel-hacking.tmpl

📁 linux 内核源代码
💻 TMPL
📖 第 1 页 / 共 3 页
字号:
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.1.2//EN"	"http://www.oasis-open.org/docbook/xml/4.1.2/docbookx.dtd" []><book id="lk-hacking-guide"> <bookinfo>  <title>Unreliable Guide To Hacking The Linux Kernel</title>    <authorgroup>   <author>    <firstname>Rusty</firstname>    <surname>Russell</surname>    <affiliation>     <address>      <email>rusty@rustcorp.com.au</email>     </address>    </affiliation>   </author>  </authorgroup>  <copyright>   <year>2005</year>   <holder>Rusty Russell</holder>  </copyright>  <legalnotice>   <para>    This documentation is free software; you can redistribute    it and/or modify it under the terms of the GNU General Public    License as published by the Free Software Foundation; either    version 2 of the License, or (at your option) any later    version.   </para>      <para>    This program is distributed in the hope that it will be    useful, but WITHOUT ANY WARRANTY; without even the implied    warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.    See the GNU General Public License for more details.   </para>      <para>    You should have received a copy of the GNU General Public    License along with this program; if not, write to the Free    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,    MA 02111-1307 USA   </para>      <para>    For more details see the file COPYING in the source    distribution of Linux.   </para>  </legalnotice>  <releaseinfo>   This is the first release of this document as part of the kernel tarball.  </releaseinfo> </bookinfo> <toc></toc> <chapter id="introduction">  <title>Introduction</title>  <para>   Welcome, gentle reader, to Rusty's Remarkably Unreliable Guide to Linux   Kernel Hacking.  This document describes the common routines and   general requirements for kernel code: its goal is to serve as a   primer for Linux kernel development for experienced C   programmers.  I avoid implementation details: that's what the   code is for, and I ignore whole tracts of useful routines.  </para>  <para>   Before you read this, please understand that I never wanted to   write this document, being grossly under-qualified, but I always   wanted to read it, and this was the only way.  I hope it will   grow into a compendium of best practice, common starting points   and random information.  </para> </chapter> <chapter id="basic-players">  <title>The Players</title>  <para>   At any time each of the CPUs in a system can be:  </para>  <itemizedlist>   <listitem>    <para>     not associated with any process, serving a hardware interrupt;    </para>   </listitem>   <listitem>    <para>     not associated with any process, serving a softirq or tasklet;    </para>   </listitem>   <listitem>    <para>     running in kernel space, associated with a process (user context);    </para>   </listitem>   <listitem>    <para>     running a process in user space.    </para>   </listitem>  </itemizedlist>  <para>   There is an ordering between these.  The bottom two can preempt   each other, but above that is a strict hierarchy: each can only be   preempted by the ones above it.  For example, while a softirq is   running on a CPU, no other softirq will preempt it, but a hardware   interrupt can.  However, any other CPUs in the system execute   independently.  </para>  <para>   We'll see a number of ways that the user context can block   interrupts, to become truly non-preemptable.  </para>    <sect1 id="basics-usercontext">   <title>User Context</title>   <para>    User context is when you are coming in from a system call or other    trap: like userspace, you can be preempted by more important tasks    and by interrupts.  You can sleep, by calling    <function>schedule()</function>.   </para>   <note>    <para>     You are always in user context on module load and unload,     and on operations on the block device layer.    </para>   </note>   <para>    In user context, the <varname>current</varname> pointer (indicating     the task we are currently executing) is valid, and    <function>in_interrupt()</function>    (<filename>include/linux/interrupt.h</filename>) is <returnvalue>false    </returnvalue>.     </para>   <caution>    <para>     Beware that if you have preemption or softirqs disabled     (see below), <function>in_interrupt()</function> will return a      false positive.    </para>   </caution>  </sect1>  <sect1 id="basics-hardirqs">   <title>Hardware Interrupts (Hard IRQs)</title>   <para>    Timer ticks, <hardware>network cards</hardware> and     <hardware>keyboard</hardware> are examples of real    hardware which produce interrupts at any time.  The kernel runs    interrupt handlers, which services the hardware.  The kernel    guarantees that this handler is never re-entered: if the same    interrupt arrives, it is queued (or dropped).  Because it    disables interrupts, this handler has to be fast: frequently it    simply acknowledges the interrupt, marks a 'software interrupt'    for execution and exits.   </para>   <para>    You can tell you are in a hardware interrupt, because     <function>in_irq()</function> returns <returnvalue>true</returnvalue>.     </para>   <caution>    <para>     Beware that this will return a false positive if interrupts are disabled      (see below).    </para>   </caution>  </sect1>  <sect1 id="basics-softirqs">   <title>Software Interrupt Context: Softirqs and Tasklets</title>   <para>    Whenever a system call is about to return to userspace, or a    hardware interrupt handler exits, any 'software interrupts'    which are marked pending (usually by hardware interrupts) are    run (<filename>kernel/softirq.c</filename>).   </para>   <para>    Much of the real interrupt handling work is done here.  Early in    the transition to <acronym>SMP</acronym>, there were only 'bottom    halves' (BHs), which didn't take advantage of multiple CPUs.  Shortly     after we switched from wind-up computers made of match-sticks and snot,    we abandoned this limitation and switched to 'softirqs'.   </para>   <para>    <filename class="headerfile">include/linux/interrupt.h</filename> lists the    different softirqs.  A very important softirq is the    timer softirq (<filename    class="headerfile">include/linux/timer.h</filename>): you can    register to have it call functions for you in a given length of    time.   </para>   <para>    Softirqs are often a pain to deal with, since the same softirq    will run simultaneously on more than one CPU.  For this reason,    tasklets (<filename    class="headerfile">include/linux/interrupt.h</filename>) are more    often used: they are dynamically-registrable (meaning you can have    as many as you want), and they also guarantee that any tasklet    will only run on one CPU at any time, although different tasklets    can run simultaneously.   </para>   <caution>    <para>     The name 'tasklet' is misleading: they have nothing to do with 'tasks',     and probably more to do with some bad vodka Alexey Kuznetsov had at the      time.    </para>   </caution>   <para>    You can tell you are in a softirq (or tasklet)    using the <function>in_softirq()</function> macro     (<filename class="headerfile">include/linux/interrupt.h</filename>).   </para>   <caution>    <para>     Beware that this will return a false positive if a bh lock (see below)     is held.    </para>   </caution>  </sect1> </chapter> <chapter id="basic-rules">  <title>Some Basic Rules</title>  <variablelist>   <varlistentry>    <term>No memory protection</term>    <listitem>     <para>      If you corrupt memory, whether in user context or      interrupt context, the whole machine will crash.  Are you      sure you can't do what you want in userspace?     </para>    </listitem>   </varlistentry>   <varlistentry>    <term>No floating point or <acronym>MMX</acronym></term>    <listitem>     <para>      The <acronym>FPU</acronym> context is not saved; even in user      context the <acronym>FPU</acronym> state probably won't      correspond with the current process: you would mess with some      user process' <acronym>FPU</acronym> state.  If you really want      to do this, you would have to explicitly save/restore the full      <acronym>FPU</acronym> state (and avoid context switches).  It      is generally a bad idea; use fixed point arithmetic first.     </para>    </listitem>   </varlistentry>   <varlistentry>    <term>A rigid stack limit</term>    <listitem>     <para>      Depending on configuration options the kernel stack is about 3K to 6K for most 32-bit architectures: it's      about 14K on most 64-bit archs, and often shared with interrupts      so you can't use it all.  Avoid deep recursion and huge local      arrays on the stack (allocate them dynamically instead).     </para>    </listitem>   </varlistentry>   <varlistentry>    <term>The Linux kernel is portable</term>    <listitem>     <para>      Let's keep it that way.  Your code should be 64-bit clean,      and endian-independent.  You should also minimize CPU      specific stuff, e.g. inline assembly should be cleanly      encapsulated and minimized to ease porting.  Generally it      should be restricted to the architecture-dependent part of      the kernel tree.     </para>    </listitem>   </varlistentry>  </variablelist> </chapter> <chapter id="ioctls">  <title>ioctls: Not writing a new system call</title>  <para>   A system call generally looks like this  </para>  <programlisting>asmlinkage long sys_mycall(int arg){        return 0; }  </programlisting>  <para>   First, in most cases you don't want to create a new system call.   You create a character device and implement an appropriate ioctl   for it.  This is much more flexible than system calls, doesn't have   to be entered in every architecture's   <filename class="headerfile">include/asm/unistd.h</filename> and   <filename>arch/kernel/entry.S</filename> file, and is much more   likely to be accepted by Linus.  </para>  <para>   If all your routine does is read or write some parameter, consider   implementing a <function>sysfs</function> interface instead.  </para>  <para>   Inside the ioctl you're in user context to a process.  When a   error occurs you return a negated errno (see   <filename class="headerfile">include/linux/errno.h</filename>),   otherwise you return <returnvalue>0</returnvalue>.  </para>  <para>   After you slept you should check if a signal occurred: the   Unix/Linux way of handling signals is to temporarily exit the   system call with the <constant>-ERESTARTSYS</constant> error.  The   system call entry code will switch back to user context, process   the signal handler and then your system call will be restarted   (unless the user disabled that).  So you should be prepared to   process the restart, e.g. if you're in the middle of manipulating   some data structure.  </para>  <programlisting>if (signal_pending())         return -ERESTARTSYS;  </programlisting>  <para>   If you're doing longer computations: first think userspace. If you   <emphasis>really</emphasis> want to do it in kernel you should   regularly check if you need to give up the CPU (remember there is   cooperative multitasking per CPU).  Idiom:  </para>  <programlisting>cond_resched(); /* Will sleep */   </programlisting>  <para>   A short note on interface design: the UNIX system call motto is   "Provide mechanism not policy".  </para> </chapter> <chapter id="deadlock-recipes">  <title>Recipes for Deadlock</title>  <para>   You cannot call any routines which may sleep, unless:  </para>  <itemizedlist>   <listitem>    <para>     You are in user context.    </para>   </listitem>   <listitem>    <para>     You do not own any spinlocks.    </para>   </listitem>   <listitem>    <para>     You have interrupts enabled (actually, Andi Kleen says     that the scheduling code will enable them for you, but     that's probably not what you wanted).    </para>   </listitem>  </itemizedlist>  <para>   Note that some functions may sleep implicitly: common ones are   the user space access functions (*_user) and memory allocation   functions without <symbol>GFP_ATOMIC</symbol>.  </para>  <para>   You should always compile your kernel   <symbol>CONFIG_DEBUG_SPINLOCK_SLEEP</symbol> on, and it will warn   you if you break these rules.  If you <emphasis>do</emphasis> break   the rules, you will eventually lock up your box.  </para>  <para>   Really.  </para> </chapter> <chapter id="common-routines">  <title>Common Routines</title>  <sect1 id="routines-printk">   <title>    <function>printk()</function>    <filename class="headerfile">include/linux/kernel.h</filename>   </title>   <para>    <function>printk()</function> feeds kernel messages to the    console, dmesg, and the syslog daemon.  It is useful for debugging    and reporting errors, and can be used inside interrupt context,    but use with caution: a machine which has its console flooded with    printk messages is unusable.  It uses a format string mostly    compatible with ANSI C printf, and C string concatenation to give    it a first "priority" argument:   </para>   <programlisting>printk(KERN_INFO "i = %u\n", i);   </programlisting>

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -