?? kernel-hacking.tmpl
字號:
<!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 + -