Linux内核:优秀的初学者教程[关闭]


52

我有兴趣修改内核内部结构,应用补丁,处理设备驱动程序和模块,这是我个人的乐趣。

是否有针对经验丰富的程序员的全面的内核黑客资源?


7
有趣的是,如何以如此之多的观点和投票来关闭一个问题。
YoMismo

1
杜拉·莱克斯,塞德·莱克斯。
亚当·马坦

1
Rectificare
sapientis

当然。毕竟,quidquid Latine dictum坐在altum videtur上。
亚当·马坦

XDDDD非常真实
YoMismo 2015年

Answers:


33
**TODO** +editPic: Linux Kernel Developer -> (Ring Layer 0)
         +addSection: Kernel Virtualization Engine

KERN_WARN_CODING_STYLE: Do not Loop unless you absolutely have to.

未初始化的推荐书籍void *i

“只有当他们拥有一定的生命时,他们才能理解书本,或者至少在没有看到并活着其中至少一部分书本之前,任何人都不会理解一本书。” –埃兹拉磅

一千个代码英里的旅程必须从一个步骤开始。如果您对以下哪几本书籍感到困惑,请放心选择任何一个。并非所有流浪者都迷路了。当所有道路最终都连接到高速公路时,随着页面的前进,您将探索内核旅程中的新事物,而不会遇到任何死角,并最终连接到code-set。警惕地阅读并记住:代码不是文学

剩下的不是事物,情感,图像,心理图片,记忆,甚至是想法。它是一个功能。某种过程。生活的一个方面可以描述为“更大”事物的功能。因此,似乎它与其他东西并不是真正的“分离”。实际上,就像刀子的功能一样-切割东西-与刀子本身并不分离。该功能目前可能正在使用或可能未使用,但可能永远不会分开使用。

Solovay Strassen非随机性原始性测试算法

Solovay Strassen去随机化原始性测试算法

阅读时不要矛盾和混淆;也不相信和理所当然;也找不到谈话和话语;但要权衡和考虑。有些书是要品尝的,其他的是要吞咽的,而有些则是要咀嚼和消化的:也就是说,有些书只能部分阅读,而有些书则要好奇阅读,但不要好奇,而有些书要全部阅读。 ,并尽职尽责。

static void tasklet_hi_action(struct softirq_action *a)
{
        struct tasklet_struct *list;

        local_irq_disable();
        list = __this_cpu_read(tasklet_hi_vec.head);
        __this_cpu_write(tasklet_hi_vec.head, NULL);
        __this_cpu_write(tasklet_hi_vec.tail, this_cpu_ptr(&tasklet_hi_vec.head));
        local_irq_enable();

        while (list) {
                struct tasklet_struct *t = list;

                list = list->next;

                if (tasklet_trylock(t)) {
                        if (!atomic_read(&t->count)) {
                                if (!test_and_clear_bit(TASKLET_STATE_SCHED,
                                                        &t->state))
                                        BUG();
                                t->func(t->data);
                                tasklet_unlock(t);
                                continue;
                        }
                        tasklet_unlock(t);
                }

                local_irq_disable();
                t->next = NULL;
                *__this_cpu_read(tasklet_hi_vec.tail) = t;
                __this_cpu_write(tasklet_hi_vec.tail, &(t->next));
                __raise_softirq_irqoff(HI_SOFTIRQ);
                local_irq_enable();
        }
}

核心Linux(5-> 1-> 3-> 2-> 7-> 4-> 6)

“自然既没有内核也没有外壳;她就是一切” –约翰·沃尔夫冈·冯·歌德

读者应该精通操作系统的概念 ; 对长期运行的流程及其与执行周期短的流程之间的差异的公正理解;满足软硬实时约束的容错能力。阅读时,重要的是要了解n/ack核心子系统中linux内核源代码以及做出的设计选择。

线程[和]信号[是]与平台有关的痛苦,绝望,恐怖和疯狂的踪迹(安东尼·巴克斯特)。话虽如此,您在进入内核之前应该是一个自我评估的C专家。您还应该对链表,堆栈,队列,红黑树,哈希函数等具有良好的经验。

volatile int i;
int main(void)
{
    int c;
    for (i=0; i<3; i++) {
        c = i&&&i;
        printf("%d\n", c);    /* find c */
    }
    return 0;
}

Linux Kernel源代码的美丽和艺术在于随之而来的故意的代码混淆。通常需要以简洁明了的方式传达涉及两个或多个运算的计算含义。在编写用于多核体系结构的代码时尤其如此。

实时系统视频讲座任务调度内存压缩内存屏障 SMP

#ifdef __compiler_offsetof
#define offsetof(TYPE,MEMBER) __compiler_offsetof(TYPE,MEMBER)
#else
#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
#endif
  1. Linux内核开发 - 罗伯特·爱
  2. 深入理解Linux内核 - 丹尼尔P.播威,马可Cesati
  3. Linux KerneL设计的艺术 - 杨丽香
  4. 专业的Linux内核架构 - 沃尔夫冈Mauerer
  5. Unix操作系统的设计 - 莫里斯J.巴赫
  6. 了解Linux的虚拟内存管理器 - 梅尔·戈曼
  7. Linux内核内幕 - 蒂格兰Aivazian
  8. 嵌入式Linux入门 - 克里斯托弗Hallinan

Linux设备驱动程序(1-> 2-> 4-> 3-> 8-> ...)

“音乐并不能帮助您。您必须严格按照自己的能力来做到这一点,才能真正专注于情感或故事的那一小部分。” -黛比·哈里

您的任务基本上是在硬件设备和软件内核之间建立高速通信接口。您应该阅读硬件参考数据表/手册,以了解设备的行为及其控制和数据状态以及提供的物理通道。从长远来看,您对特定体系结构的汇编知识以及对VLSI硬件描述语言的充分了解将可以为您提供帮助,例如VHDL或Verilog。

:但是,为什么我必须阅读硬件规格?

:因为“软件无法弥合碳和硅的鸿沟”-Rahul Sonnad

但是,以上内容对于计算算法驱动程序代码 - 下半部分处理)没有问题,因为可以在通用图灵机上对其进行完全模拟。如果计算结果在数学范围内成立,那么可以肯定的是,在物理范围内也是如此。

关于Linux设备驱动程序的视频讲座(第17和18节),嵌入式KMS驱动程序剖析引脚控制和GPIO更新通用时钟框架编写真正的Linux驱动程序-Greg KH

static irqreturn_t phy_interrupt(int irq, void *phy_dat)
{
         struct phy_device *phydev = phy_dat;

         if (PHY_HALTED == phydev->state)
                 return IRQ_NONE;                /* It can't be ours.  */

         /* The MDIO bus is not allowed to be written in interrupt
          * context, so we need to disable the irq here.  A work
          * queue will write the PHY to disable and clear the
          * interrupt, and then reenable the irq line.
          */
         disable_irq_nosync(irq);
         atomic_inc(&phydev->irq_disable);

         queue_work(system_power_efficient_wq, &phydev->phy_queue);

         return IRQ_HANDLED;
}
  1. Linux设备驱动程序 - 乔纳森·科比特,亚历山德罗Rubini和葛雷格·克罗哈曼
  2. 基本的Linux设备驱动程序 - Sreekrishnan Venkateswaran
  3. 编写Linux设备驱动程序 - 杰里Cooperstein
  4. Linux内核模块编程指南 - 彼得·杰伊·萨尔兹曼,迈克尔·布里安大利波默朗茨
  5. Linux的PCMCIA程序员指南 - 大卫·海因兹
  6. Linux的SCSI编程HOWTO - 海科Eibfeldt
  7. 串行编程指南POSIX操作系统 - 迈克尔·R.甜
  8. Linux的图形驱动程序:导论 - 斯特凡Marchesin
  9. 编程指南Linux的USB设备驱动程序 - 德特勒夫的Fliegl
  10. Linux内核设备型号 - 帕特里克Mochel

内核联网(1-> 2-> 3-> ...)

“称它为氏族,称其为网络,称其为部落,称其为家庭:无论您叫什么,无论您是谁,都需要一个。”-简·霍华德

了解内核中的数据包漫游是了解内核网络的关键。如果我们想了解Netfilter或IPSec内部以及其他内容,则必须了解它。linux内核网络层的两个最重要的结构是:struct sk_buffstruct net_device

static inline int sk_hashed(const struct sock *sk)
{
        return !sk_unhashed(sk);
} 
  1. 了解Linux网络内幕 - 基督教Benvenuti酒店
  2. Linux内核网络:实现与理论 - 拉米·罗森
  3. UNIX网络编程 - 理查德·史蒂文斯
  4. 权威指南Linux网络编程 - 凯尔·戴维斯,约翰·W·特纳,弥敦道Yocom
  5. Linux的TCP / IP协议栈:网络的嵌入式系统 - 托马斯F.赫伯特
  6. Linux的Socket编程实例通过 - 沃伦·W·盖伊
  7. Linux的高级路由和流量控制HOWTO - 伯特·休伯特

内核调试(1-> 4-> 9-> ...)

除非与之进行确切的交流,否则必然会造成麻烦。〜艾伦·图灵,关于计算机

Brian W. Kernighan在Unix for Beginners(1979)一文中说:“最有效的调试工具仍然是经过仔细考虑,再加上明智放置的打印语句”。知道要收集什么将帮助您快速获取正确的数据以进行快速诊断。伟大的计算机科学家Edsger Dijkstra曾经说过,测试可以证明存在错误,但不能证明没有错误。良好的调查实践应在快速解决问题的需求,建立技能的需求以及有效利用主题专家之间取得平衡。

有时候,当您触底时,似乎没有任何效果,并且用尽了所有选择。然后开始真正的调试。错误可能会导致您需要从无效解决方案的修复中脱离出来。

有关内核调试和性能分析内核转储分析使用GDB进行多核调试控制多核竞争条件调试电子设备的视频讲座

/* Buggy Code -- Stack frame problem
 * If you require information, do not free memory containing the information
 */
char *initialize() {
  char string[80];
  char* ptr = string;
  return ptr;
}

int main() {
  char *myval = initialize();
  do_something_with(myval);
}
/*  “When debugging, novices insert corrective code; experts remove defective code.”
 *     – Richard Pattis
#if DEBUG
 printk("The above can be considered as Development and Review in Industrial Practises");
#endif
 */
  1. Linux调试和性能调整 - 史蒂夫最佳
  2. Linux应用程序的技术调试 - 奥勒梅林特
  3. 调试用GDB:GNU的源代码级调试 - 罗兰H.佩施
  4. 调试嵌入式Linux - Christopher Hallinan
  5. 调试的艺术与GDB,DDD和Eclipse - 诺曼S. Matloff
  6. 为什么程序将会失败:指南系统调试 - 安德烈亚斯·泽勒
  7. 软件驱邪:一种用于调试和优化遗留代码手册 - 比尔·布拉登
  8. 调试:寻找最难以捉摸的软件和硬件问题 - 戴维·J·阿加斯
  9. 调试通过思考:多学科方法 - 罗伯特·查尔斯·梅茨格
  10. 找到了这个错误:不正确的程序的书 - 亚当·巴尔

文件系统(1-> 2-> 6-> ...)

“我希望拥有虚拟内存,至少要与文件系统结合使用”。肯·汤普森

在UNIX系统上,所有内容都是文件。如果某物不是文件,则它是一个进程,但命名管道和套接字除外。在文件系统中,文件由表示,这inode是一种序列号,其中包含有关构成文件的实际数据的信息。Linux虚拟文件系统VFS在安装和使用每个文件系统时,会将信息缓存在内存中。在创建,写入和删除文件和目录时,由于修改了这些缓存中的数据,因此必须格外小心地正确更新文件系统。这些缓存中最重要的是缓冲区缓存,它已集成到各个文件系统访问其底层块存储设备的方式中。

关于存储系统的视频讲座闪存友好文件系统

long do_sys_open(int dfd, const char __user *filename, int flags, umode_t mode)
{
        struct open_flags op;
        int fd = build_open_flags(flags, mode, &op);
        struct filename *tmp;

        if (fd)
                return fd;

        tmp = getname(filename);
        if (IS_ERR(tmp))
                return PTR_ERR(tmp);

        fd = get_unused_fd_flags(flags);
        if (fd >= 0) {
                struct file *f = do_filp_open(dfd, tmp, &op);
                if (IS_ERR(f)) {
                        put_unused_fd(fd);
                        fd = PTR_ERR(f);
                } else {
                        fsnotify_open(f);
                        fd_install(fd, f);
                }
        }
        putname(tmp);
        return fd;
}

SYSCALL_DEFINE3(open, const char __user *, filename, int, flags, umode_t, mode)
{
        if (force_o_largefile())
                flags |= O_LARGEFILE;

        return do_sys_open(AT_FDCWD, filename, flags, mode);
}
  1. Linux文件系统 - 摩西·酒吧
  2. Linux文件系统 - 威廉·冯·哈根
  3. UNIX文件系统的演进,设计和实施 - 史蒂夫D.佩特
  4. 实用的文件系统设计 - 多米尼克·詹保罗
  5. 文件系统取证分析 - 布赖恩·卡里尔
  6. Linux文件系统层次结构 - 平阮
  7. BTRFS:Linux的B树文件系统 - 辖Rodeh
  8. StegFS:Linux的隐写的文件系统 - 安德鲁D.麦当劳,马库斯·库恩G。

安全性(1-> 2-> 8-> 4-> 3-> ...)

“ UNIX并非旨在阻止其用户执行愚蠢的操作,因为这也将阻止他们执行聪明的操作”。—道格·格温(Doug Gwyn)

如果不使用任何技术,则无济于事。道德随着技术而改变。

F×S = k ”自由与安全的乘积是一个常数。-尼文定律

密码学构成了在线信任的基础。黑客正在利用技术,物理或基于人的元素中的安​​全控制。保护内核免受其他正在运行的程序的侵害,是朝着建立安全,稳定的系统的第一步,但这显然是不够的:在不同的用户区域应用程序之间也必须存在一定程度的保护。漏洞可以针对本地或远程服务。

“您无法破坏自己的命运,蛮力……您需要一扇后门,一条通向生活的通道。” ― Clyde Dsouza

计算机不解决问题,而是执行解决方案。在每个非确定性算法代码的背后,都有一个坚定的头脑。 -/ var / log / dmesg

有关密码学和网络安全安全性命名空间防止远程攻击的保护安全嵌入式Linux的视频讲座

env x='() { :;}; echo vulnerable' bash -c "echo this is a test for Shellsock"
  1. 黑客:剥削的艺术 - 乔恩·埃里克森
  2. rootkit的阿森纳:逃亡Evasion在系统的黑暗角落 - 比尔·布拉登
  3. 黑客大曝光:网络安全机密 - 斯图尔特·麦克卢尔,乔尔Scambray,乔治·库尔茨
  4. 指南内核开发:进攻核心 - 恩里科·佩拉,的Massimiliano Oldani
  5. 记忆取证的艺术 - 迈克尔·海尔·利格Michael Hale Ligh),安德鲁·凯斯(Andrew Case),杰米·利维(Jamie Levy),亚伦·沃尔特斯(AAron Walters)
  6. 实用逆向工程 - 布鲁斯荡,亚历山大Gazet,埃利亚斯Bachaalany
  7. 实用恶意软件分析 - 迈克尔·西科尔斯基,安德鲁·霍尼格
  8. 最高的Linux安全性:保护Linux服务器的黑客指南 - 匿名
  9. Linux安全 - 克雷格·亨特
  10. 真实世界的Linux安全 - 鲍勃Toxen

内核源(0.11-> 2.4-> 2.6-> 3.18)

“就像wine一样,内核编程的掌握程度会随着时间而成熟。但是,与wine不同,它在过程中会变得更甜。” -劳伦斯·穆切卡(Lawrence Mucheka)

您可能不认为程序员是艺​​术家,但是编程是一个极富创造力的职业。这是基于逻辑的创造力。计算机科学教育不能使任何人成为专家程序员,就像学习画笔和颜料可以使某人成为专家画家一样。如您所知,知道路径和走路径是有区别的。卷起袖子并掌握内核源代码对您至关重要。最后,借助您由此获得的内核知识,无论您走到哪里,都将发光

不成熟的编码员会模仿;成熟的编码员偷窃;糟糕的编码人员会掩盖他们的工作,而好的编码人员会使它变得更好,或者至少有所不同。优秀的编码员将盗窃案焊接成一种独特的感觉,与被撕破的感觉完全不同。

关于内核食谱的视频讲座

linux-0.11
├── boot
│   ├── bootsect.s      head.s      setup.s
├── fs
│   ├── bitmap.c    block_dev.c buffer.c        char_dev.c  exec.c
│   ├── fcntl.c     file_dev.c  file_table.c    inode.c     ioctl.c
│   ├── namei.c     open.c      pipe.c          read_write.c
│   ├── stat.c      super.c     truncate.c
├── include
│   ├── a.out.h     const.h     ctype.h     errno.h     fcntl.h
│   ├── signal.h    stdarg.h    stddef.h    string.h    termios.h
│   ├── time.h      unistd.h    utime.h
│   ├── asm
│   │   ├── io.h    memory.h    segment.h   system.h
│   ├── linux
│   │   ├── config.h    fdreg.h fs.h    hdreg.h     head.h
│   │   ├── kernel.h    mm.h    sched.h sys.h       tty.h
│   ├── sys
│   │   ├── stat.h      times.h types.h utsname.h   wait.h
├── init
│   └── main.c
├── kernel
│   ├── asm.s       exit.c      fork.c      mktime.c    panic.c
│   ├── printk.c    sched.c     signal.c    sys.c       system_calls.s
│   ├── traps.c     vsprintf.c
│   ├── blk_drv
│   │   ├── blk.h   floppy.c    hd.c    ll_rw_blk.c     ramdisk.c
│   ├── chr_drv
│   │   ├── console.c   keyboard.S  rs_io.s
│   │   ├── serial.c    tty_io.c    tty_ioctl.c
│   ├── math
│   │   ├── math_emulate.c
├── lib
│   ├── close.c  ctype.c  dup.c     errno.c  execve.c  _exit.c
│   ├── malloc.c open.c   setsid.c  string.c wait.c    write.c
├── Makefile
├── mm
│   ├── memory.c page.s
└── tools
    └── build.c
  1. 初学者从Linux 0.11源代码开始(不到20,000行源代码)。经过20年的发展,与Linux 0.11相比,Linux变得非常庞大,复杂且难以学习。但是设计概念和主要结构没有根本变化。学习Linux 0.11仍然具有重要的实际意义。
  2. 内核黑客的强制性阅读=> Linux_source_dir/Documentation/*
  3. 您应该至少已订阅一个内核邮件列表并处于活动状态。从内核新手开始。
  4. 您无需阅读完整的源代码。熟悉内核API及其用法之后,直接从您感兴趣的子系统的源代码开始。您也可以从编写自己的即插即用模块开始尝试内核。
  5. 设备驱动程序编写者可以通过拥有自己的专用硬件来受益。从Raspberry Pi开始。

2
谢谢!这是一个相当全面的答案。请看一下
亚当·马坦

1
这个答案是惊人的
pkqxdd

惊人的答案!我还创建了一个我可能会感兴趣的教程:github.com/cirosantilli/linux-kernel-module-cheat它包含一个高度自动化的设置,可以为您构建Linux内核,QEMU和根文件系统。包括GDB Linux内核步骤调试设置。
Ciro Santilli新疆改造中心法轮功六四事件


5

我建议您阅读Greg Kroah-Hartman撰写的“ 坚果壳中的Linux内核 ”和Robert Love 撰写的“ 了解Linux内核 ”。必须读:)



@Josh这些书是5-6年前写的,它们仍然是热门话题吗?
Alex Bolotov 2012年

我不能以任何合理的信誉回答这个问题:((其他责任消耗了我的时间,我从没读过它。希望wzzrd能够看到这些评论并发表评论。)
Joshua Enfield

1
是的,这些书仍然有用。许多细节已经改变了,面目全非。查看上面提到的内核新手页面(或lwn.net的内核页面,进行深入讨论和重大新闻)。
vonbrand

4

Linux设备驱动程序是另一个很好的资源。这将为您提供另一种进入内部运作方式的方法。从序言:

从表面上看,这是一本有关为Linux系统编写设备驱动程序的书。当然,这是一个值得的目标。新硬件产品的流量可能不会很快放缓,并且有人将不得不使所有这些新小工具都可以在Linux上使用。但是本书还涉及Linux内核如何工作以及如何使其工作适应您的需求或兴趣。Linux是一个开放系统。希望通过这本书,它对更多的开发人员社区更加开放和易于使用。


我总是发现面向目标的学习对我来说比抽象学习更有生产力。LDD书给了我机会,可以咬掉足够小的一块来取得进展。
拉里·史密斯米尔


2

Linux Kernel 2.4 Internals是另一个在线资源。从启动开始,似乎采取了一种非常“基础”的方法。这里是目录:

  1. 正在启动
    • 1.1构建Linux内核映像
    • 1.2引导:概述
    • 1.3引导:BIOS POST
    • 1.4引导:引导程序和设置
    • 1.5使用LILO作为引导程序
    • 1.6高级初始化
    • 1.7在x86上启动SMP
    • 1.8释放初始化数据和代码
    • 1.9处理内核命令行
  2. 流程和中断管理
    • 2.1任务结构和过程表
    • 2.2创建和终止任务和内核线程
    • 2.3 Linux Scheduler
    • 2.4 Linux链表实现
    • 2.5等待队列
    • 2.6内核计时器
    • 2.7下半部
    • 2.8任务队列
    • 2.9小任务
    • 2.10 Softirqs
    • 2.11如何在i386体系结构上实现系统调用?
    • 2.12原子操作
    • 2.13自旋锁,读写自旋锁和大读者自旋锁
    • 2.14信号量和读/写信号量
    • 2.15内核对加载模块的支持
  3. 虚拟文件系统(VFS)
    • 3.1索引节点缓存和与Dcache的交互
    • 3.2文件系统注册/注销
    • 3.3文件描述符管理
    • 3.4文件结构管理
    • 3.5超级块和挂载点管理
    • 3.6示例虚拟文件系统:pipefs
    • 3.7磁盘文件系统示例:BFS
    • 3.8执行域和二进制格式
  4. Linux页面缓存
  5. IPC机制
    • 5.1信号量
    • 5.2消息队列
    • 5.3共享内存
    • 5.4 Linux IPC原语

而且,为了使它更甜蜜,有一个由Robert Love发行的新Linux Kernel Development第三版,Slashdot对此进行了评论。


1

从Claudia Salzberg等人的Linux Kernel Primer开始。对于初学者来说是个不错的开始。Robert Love的书绝对不是初学者应该开始的书。后本书高于中级水平。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.