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

📄 kernel-hacking.tmpl

📁 嵌入式系统设计与实例开发实验教材二源码 多线程应用程序设计 串行端口程序设计 AD接口实验 CAN总线通信实验 GPS通信实验 Linux内核移植与编译实验 IC卡读写实验 SD驱动使
💻 TMPL
📖 第 1 页 / 共 4 页
字号:
<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook V3.1//EN"[]><book id="lk-hacking-guide"> <bookinfo>  <title>Unreliable Guide To Hacking The Linux Kernel</title>    <authorgroup>   <author>    <firstname>Paul</firstname>    <othername>Rusty</othername>    <surname>Russell</surname>    <affiliation>     <address>      <email>rusty@rustcorp.com.au</email>     </address>    </affiliation>   </author>  </authorgroup>  <copyright>   <year>2001</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 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, tasklet or bh;    </para>   </listitem>   <listitem>    <para>     running in kernel space, associated with a process;    </para>   </listitem>   <listitem>    <para>     running a process in user space.    </para>   </listitem>  </itemizedlist>  <para>   There is a strict ordering between these: other than the last   category (userspace) each can only be pre-empted by those above.   For example, while a softirq is running on a CPU, no other   softirq will pre-empt 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: you can sleep, and you own the CPU (except for    interrupts) until you call <function>schedule()</function>.      In other words, user context (unlike userspace) is not pre-emptable.   </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/asm/hardirq.h</filename>) is <returnvalue>false    </returnvalue>.     </para>   <caution>    <para>     Beware that if you have interrupts or bottom halves 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 another    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: Bottom Halves, Tasklets, softirqs</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.   </para>   <para>    <filename class=headerfile>include/linux/interrupt.h</filename> lists the     different BH's.  No matter how many CPUs you have, no two BHs will run at     the same time. This made the transition to SMP simpler, but sucks hard for    scalable performance.  A very important bottom half is the timer    BH (<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>    2.3.43 introduced softirqs, and re-implemented the (now    deprecated) BHs underneath them.  Softirqs are fully-SMP    versions of BHs: they can run on as many CPUs at once as    required.  This means they need to deal with any races in shared    data using their own locks.  A bitmask is used to keep track of    which are enabled, so the 32 available softirqs should not be    used up lightly.  (<emphasis>Yes</emphasis>, people will    notice).   </para>   <para>    tasklets (<filename class=headerfile>include/linux/interrupt.h</filename>)     are like softirqs, except 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 (unlike different BHs).     </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 bottom half, or tasklet)    using the <function>in_softirq()</function> macro     (<filename class=headerfile>include/asm/softirq.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>      The kernel stack is about 6K in 2.2 (for most      architectures: it's about 14K on the Alpha), and 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 int 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>sysctl</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>

⌨️ 快捷键说明

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