.. include:: ../disclaimer-zh_CN.rst :Original: Documentation/kernel-hacking/hacking.rst :译者: å´æƒ³æˆ Wu XiangCheng <bobwxc@email.cn> ============== å†…æ ¸éª‡å®¢æŒ‡åŒ— ============== :作者: Rusty Russell 引言 ===== 欢迎咱优雅的读者们æ¥é˜…读Rustyçš„éžå¸¸ä¸é 谱的Linuxå†…æ ¸éª‡å®¢ï¼ˆHacking)指å—。本文 æè¿°äº†å†…æ ¸ä»£ç 的常è§ä¾‹ç¨‹å’Œä¸€èˆ¬è¦æ±‚ï¼šå…¶ç›®æ ‡æ˜¯å¼•å¯¼æœ‰ç»éªŒçš„C程åºå‘˜å…¥é—¨Linuxå†…æ ¸ å¼€å‘。我回é¿äº†å®žçŽ°ç»†èŠ‚:这是代ç è¦åšçš„,也忽略了很多有用的例程。 åœ¨ä½ è¯»è¿™ç¯‡æ–‡ç« ä¹‹å‰ï¼Œè¯·ç†è§£æˆ‘从æ¥æ²¡æœ‰æƒ³è¿‡è¦å†™è¿™ç¯‡æ–‡ç« ï¼Œå› ä¸ºæˆ‘çš„èµ„åŽ†å¤ªä½Žäº†ï¼› ä½†æˆ‘ä¸€ç›´æƒ³è¯»è¿™æ ·çš„æ–‡ç« ï¼Œè‡ªå·±å†™æ˜¯å”¯ä¸€çš„æ–¹æ³•ã€‚æˆ‘å¸Œæœ›å®ƒèƒ½æˆé•¿ä¸ºä¸€ä¸ªæœ€ä½³å®žè·µã€ 通用起点和其他信æ¯çš„汇编。 玩家 ======= 在任何时候,系统ä¸çš„æ¯ä¸ªCPU都å¯ä»¥ï¼š - ä¸Žä»»ä½•è¿›ç¨‹æ— å…³ï¼ŒæœåŠ¡äºŽç¡¬ä»¶ä¸æ–ï¼› - ä¸Žä»»ä½•è¿›ç¨‹æ— å…³ï¼ŒæœåŠ¡äºŽè½¯ä»¶ä¸æ–(softirq)或å任务(tasklet); - è¿è¡ŒäºŽå†…æ ¸ç©ºé—´ä¸ï¼Œä¸Žè¿›ç¨‹ï¼ˆç”¨æˆ·ä¸Šä¸‹æ–‡ï¼‰ç›¸å…³è”ï¼› - 在用户空间ä¸è¿è¡Œè¿›ç¨‹ã€‚ 它们之间有优先级顺åºã€‚最下é¢çš„两个å¯ä»¥äº’相抢å ,但上é¢ä¸ºä¸¥æ ¼çš„层次结构: æ¯ä¸ªå±‚级åªèƒ½è¢«ä¸Šæ–¹çš„抢å 。例如,当一个软ä¸æ–在CPU上è¿è¡Œæ—¶ï¼Œæ²¡æœ‰å…¶ä»–软ä¸æ– 会抢å 它,但是硬件ä¸æ–å¯ä»¥æŠ¢å 它。ä¸è¿‡ï¼Œç³»ç»Ÿä¸çš„任何其他CPU都是独立执行的。 我们将会看到许多方法,用户上下文å¯ä»¥é˜»æ¢ä¸æ–,从而æˆä¸ºçœŸæ£çš„ä¸å¯æŠ¢å 。 用户上下文 ------------ 用户上下文是指当您从系统调用或其他陷阱进入时:就åƒç”¨æˆ·ç©ºé—´ä¸€æ ·ï¼Œæ‚¨å¯ä»¥è¢«æ›´ é‡è¦çš„任务和ä¸æ–抢å 。您å¯ä»¥é€šè¿‡è°ƒç”¨ :c:func:`schedule()` 进行ç¡çœ 。 .. note:: 在模å—åŠ è½½å’Œå¸è½½ä»¥åŠå—设备层上的æ“ä½œæ—¶ï¼Œä½ å§‹ç»ˆå¤„äºŽç”¨æˆ·ä¸Šä¸‹æ–‡ä¸ã€‚ 在用户上下文ä¸ï¼Œå½“å‰ ``current`` 指针(指示我们当å‰æ£åœ¨æ‰§è¡Œçš„任务)是有效的, 且 :c:func:`in_interrupt()` ( ``include/linux/preempt.h`` )值为éžï¼ˆfalse)。 .. warning:: 请注æ„,如果您ç¦ç”¨äº†æŠ¢å 或软ä¸æ–(è§ä¸‹æ–‡ï¼‰ï¼Œ:c:func:`in_interrupt()` 会 返回å‡é˜³æ€§ã€‚ 硬件ä¸æ–(Hard IRQs) ---------------------- åƒå®šæ—¶å™¨ã€ç½‘å¡å’Œé”®ç›˜ç‰éƒ½æ˜¯å¯èƒ½åœ¨ä»»æ„时刻产生ä¸æ–çš„çœŸå®žç¡¬ä»¶ã€‚å†…æ ¸è¿è¡Œä¸æ– 处ç†ç¨‹åºï¼Œä¸ºç¡¬ä»¶æä¾›æœåŠ¡ã€‚å†…æ ¸ç¡®ä¿å¤„ç†ç¨‹åºæ°¸è¿œä¸ä¼šé‡å…¥ï¼šå¦‚果相åŒçš„ä¸æ–到达, å®ƒå°†è¢«æŽ’é˜Ÿï¼ˆæˆ–ä¸¢å¼ƒï¼‰ã€‚å› ä¸ºå®ƒä¼šå…³é—ä¸æ–,所以处ç†ç¨‹åºå¿…须很快:通常它åªæ˜¯ 确认ä¸æ–ï¼Œæ ‡è®°ä¸€ä¸ªâ€œè½¯ä»¶ä¸æ–â€ä»¥æ‰§è¡Œå¹¶é€€å‡ºã€‚ 您å¯ä»¥é€šè¿‡ in_hardirq() 返回真æ¥åˆ¤æ–您处于硬件ä¸æ–状æ€ã€‚ .. warning:: 请注æ„,如果ä¸æ–被ç¦ç”¨ï¼Œè¿™å°†è¿”回å‡é˜³æ€§ï¼ˆè§ä¸‹æ–‡ï¼‰ã€‚ 软件ä¸æ–上下文:软ä¸æ–(Softirqs)与å任务(Tasklets) ------------------------------------------------------- 当系统调用å³å°†è¿”回用户空间或硬件ä¸æ–处ç†ç¨‹åºé€€å‡ºæ—¶ï¼Œä»»ä½•æ ‡è®°ä¸ºæŒ‚起(通常通 过硬件ä¸æ–)的“软件ä¸æ–â€å°†è¿è¡Œï¼ˆ ``kernel/softirq.c`` )。 æ¤å¤„完æˆäº†è®¸å¤šçœŸæ£çš„ä¸æ–处ç†å·¥ä½œã€‚在å‘SMP过渡的早期,åªæœ‰â€œbottom halvesä¸‹åŠ éƒ¨â€ï¼ˆBHsï¼‰æœºåˆ¶ï¼Œæ— æ³•åˆ©ç”¨å¤šä¸ªCPU的优势。在从那些一团糟的就电脑切æ¢è¿‡æ¥åŽä¸ä¹…, 我们放弃了这个é™åˆ¶ï¼Œè½¬è€Œä½¿ç”¨â€œè½¯ä¸æ–â€ã€‚ ``include/linux/interrupt.h`` 列出了ä¸åŒçš„软ä¸æ–。定时器软ä¸æ–是一个éžå¸¸é‡è¦ 的软ä¸æ–( ``include/linux/timer.h`` ):您å¯ä»¥æ³¨å†Œå®ƒä»¥åœ¨ç»™å®šæ—¶é—´åŽä¸ºæ‚¨è°ƒç”¨ 函数。 软ä¸æ–通常是一个很难处ç†çš„é—®é¢˜ï¼Œå› ä¸ºåŒä¸€ä¸ªè½¯ä¸æ–å°†åŒæ—¶åœ¨å¤šä¸ªCPU上è¿è¡Œã€‚å› æ¤ï¼Œ å任务( ``include/linux/interrupt.h`` )更常用:它们是动æ€å¯æ³¨å†Œçš„(æ„å‘³ç€ æ‚¨å¯ä»¥æ‹¥æœ‰ä»»æ„æ•°é‡ï¼‰ï¼Œå¹¶ä¸”它们还ä¿è¯ä»»ä½•å任务都åªèƒ½åœ¨ä¸€ä¸ªCPU上è¿è¡Œï¼Œä¸åŒçš„ å任务也å¯ä»¥åŒæ—¶è¿è¡Œã€‚ .. warning:: “taskletâ€è¿™ä¸ªåå—是误导性的:它们与“任务â€æ— 关,å¯èƒ½æ›´å¤šä¸Žå½“æ—¶ 阿列克谢·库兹涅ä½å¤«äº«ç”¨çš„糟糕ä¼ç‰¹åŠ 有关。 ä½ å¯ä»¥ä½¿ç”¨ :c:func:`in_softirq()` å®ï¼ˆ ``include/linux/preempt.h`` )æ¥ç¡®è®¤ 是å¦å¤„于软ä¸æ–(或å任务)ä¸ã€‚ .. warning:: 注æ„,如果æŒæœ‰ :ref:`bottom half lock <local_bh_disable_zh>` é”,这将返回 å‡é˜³æ€§ã€‚ 一些基本规则 ================ 缺少内å˜ä¿æŠ¤ å¦‚æžœä½ æŸå了内å˜ï¼Œæ— 论是在用户上下文还是ä¸æ–上下文ä¸ï¼Œæ•´ä¸ªæœºå™¨éƒ½ä¼šå´©æºƒã€‚ ä½ ç¡®å®šä½ ä¸èƒ½åœ¨ç”¨æˆ·ç©ºé—´é‡Œåšä½ 想åšçš„事å—? 缺少浮点或MMX FPU上下文ä¸ä¼šè¢«ä¿å˜ï¼›å³ä½¿åœ¨ç”¨æˆ·ä¸Šä¸‹æ–‡ä¸ï¼ŒFPU状æ€ä¹Ÿå¯èƒ½ä¸Žå½“å‰è¿›ç¨‹ä¸ä¸€è‡´ï¼š 您会弄乱æŸäº›ç”¨æˆ·è¿›ç¨‹çš„FPU状æ€ã€‚如果真的è¦è¿™æ ·åšï¼Œå°±å¿…须显å¼åœ°ä¿å˜/æ¢å¤ 完整的FPU状æ€ï¼ˆå¹¶é¿å…上下文切æ¢ï¼‰ã€‚这通常ä¸æ˜¯ä¸ªå¥½ä¸»æ„;请优先用定点算法。 ä¸¥æ ¼çš„å †æ ˆé™åˆ¶ 对于大多数32ä½ä½“ç³»ç»“æž„ï¼Œæ ¹æ®é…置选项的ä¸åŒå†…æ ¸å †æ ˆå¤§çº¦ä¸º3K到6K;对于大 多数64ä½æœºå™¨ï¼Œå†…æ ¸å †æ ˆå¤§çº¦ä¸º14K,并且ç»å¸¸ä¸Žä¸æ–å…±äº«ï¼Œå› æ¤ä½ æ— æ³•ä½¿ç”¨å…¨éƒ¨ã€‚ 应é¿å…æ·±åº¦é€’å½’å’Œæ ˆä¸Šçš„å·¨åž‹æœ¬åœ°æ•°ç»„ï¼ˆç”¨åŠ¨æ€åˆ†é…它们æ¥ä»£æ›¿ï¼‰ã€‚ Linuxå†…æ ¸æ˜¯å¯ç§»æ¤çš„ å°±è¿™æ ·å§ã€‚您的代ç 应该是纯64ä½çš„,并且ä¸ä¾èµ–于å—节åºï¼ˆendian)。您还应该 å°½é‡å‡å°‘CPU特定的东西,例如内è”汇编(inline assembly)应该被干净地å°è£…å’Œ 最å°åŒ–以便于移æ¤ã€‚一般æ¥è¯´ï¼Œå®ƒåº”该局é™äºŽå†…æ ¸æ ‘ä¸æœ‰ä½“系结构ä¾èµ–的部分。 输入输出控制(ioctls):é¿å…编写新的系统调用 ============================================== 系统调用(system call)通常看起æ¥åƒè¿™æ ·:: asmlinkage long sys_mycall(int arg) { return 0; } é¦–å…ˆï¼Œåœ¨å¤§å¤šæ•°æƒ…å†µä¸‹ï¼Œæ‚¨æ— éœ€åˆ›å»ºæ–°çš„ç³»ç»Ÿè°ƒç”¨ã€‚åˆ›å»ºä¸€ä¸ªå—符设备并为其实现适当 的输入输出控制(ioctls)。这比系统调用çµæ´»å¾—多,ä¸å¿…写进æ¯ä¸ªä½“系结构的 ``include/asm/unistd.h`` å’Œ ``arch/kernel/entry.S`` 文件里,而且更容易被Linus 接å—。 如果您的程åºæ‰€åšçš„åªæ˜¯è¯»å–或写入一些å‚数,请考虑实现 :c:func:`sysfs()` 接å£ã€‚ 在输入输出控制ä¸ï¼Œæ‚¨å¤„于进程的用户上下文。出现错误时,返回一个负的错误å‚æ•° (errno,请å‚阅 ``include/uapi/asm-generic/errno-base.h`` 〠``include/uapi/asm-generic/errno.h`` å’Œ ``include/linux/errno.h`` ),å¦åˆ™è¿” 回0。 在ç¡çœ 之åŽï¼Œæ‚¨åº”该检查是å¦å‡ºçŽ°äº†ä¿¡å·ï¼šUnix/Linux处ç†ä¿¡å·çš„方法是暂时退出系统 调用,并返回 ``-ERESTARTSYS`` 错误。系统调用入å£ä»£ç 将切æ¢å›žç”¨æˆ·ä¸Šä¸‹æ–‡ï¼Œå¤„ç† ä¿¡å·å¤„ç†ç¨‹åºï¼Œç„¶åŽç³»ç»Ÿè°ƒç”¨å°†é‡æ–°å¯åŠ¨ï¼ˆé™¤éžç”¨æˆ·ç¦ç”¨äº†è¯¥åŠŸèƒ½ï¼‰ã€‚å› æ¤ï¼Œæ‚¨åº”该准 备好处ç†é‡æ–°å¯åŠ¨ï¼Œä¾‹å¦‚若您处ç†æŸäº›æ•°æ®ç»“构到一åŠã€‚ :: if (signal_pending(current)) return -ERESTARTSYS; å¦‚æžœä½ è¦åšæ›´é•¿æ—¶é—´çš„è®¡ç®—ï¼šä¼˜å…ˆè€ƒè™‘ç”¨æˆ·ç©ºé—´ã€‚å¦‚æžœä½ çœŸçš„æƒ³åœ¨å†…æ ¸ä¸åšè¿™ä»¶äº‹ï¼Œä½ åº”è¯¥å®šæœŸæ£€æŸ¥ä½ æ˜¯å¦éœ€è¦è®©å‡ºCPU(请记得æ¯ä¸ªCPU都有å作多任务)。 ä¹ æƒ¯ç”¨æ³•:: cond_resched(); /* Will sleep */ 接å£è®¾è®¡çš„å°æ³¨é‡Šï¼šUNIXç³»ç»Ÿè°ƒç”¨çš„æ ¼è¨€æ˜¯â€œæ供机制而ä¸æ˜¯ç–ç•¥ Provide mechanism not policyâ€ã€‚ æ»é”的“é…方†==================== 您ä¸èƒ½è°ƒç”¨ä»»ä½•å¯èƒ½ç¡çœ 的程åºï¼Œé™¤éžï¼š - 您处于用户上下文ä¸ã€‚ - ä½ æœªæ‹¥æœ‰ä»»ä½•è‡ªæ—‹é”。 - 您已ç»å¯ç”¨ä¸æ–(实际上,Andi Kleen说调度代ç 将为您å¯ç”¨å®ƒä»¬ï¼Œä½†è¿™å¯èƒ½ä¸æ˜¯ 您想è¦çš„)。 注æ„,有些函数å¯èƒ½éšå¼åœ°ç¡çœ :常è§çš„是用户空间访问函数(\*_user)和没有 ``GFP_ATOMIC`` 的内å˜åˆ†é…函数。 您应该始终打开 ``CONFIG_DEBUG_ATOMIC_SLEEP`` 项æ¥ç¼–è¯‘å†…æ ¸ï¼Œå¦‚æžœæ‚¨è¿å这些 规则,它将è¦å‘Šæ‚¨ã€‚å¦‚æžœä½ **真的** è¿åäº†è§„åˆ™ï¼Œä½ æœ€ç»ˆä¼šé”ä½ä½ 的电脑。 çœŸçš„ä¼šè¿™æ ·ã€‚ 常用函数/ç¨‹åº =============== :c:func:`printk()` ------------------ 定义于 ``include/linux/printk.h`` :c:func:`printk()` å°†å†…æ ¸æ¶ˆæ¯æ供给控制å°ã€dmesgå’Œsyslog守护进程。它对于调 试和报告错误很有用,并且å¯ä»¥åœ¨ä¸æ–上下文ä¸ä½¿ç”¨ï¼Œä½†æ˜¯ä½¿ç”¨æ—¶è¦å°å¿ƒï¼šå¦‚果机器 的控制å°ä¸å……æ–¥ç€printk消æ¯åˆ™ä¼šæ— 法使用。它使用与ANSI C printfåŸºæœ¬å…¼å®¹çš„æ ¼å¼ å—符串,并通过Cå—符串串è”为其æ供第一个“优先â€å‚æ•°:: printk(KERN_INFO "i = %u\n", i); å‚è§ ``include/linux/kern_levels.h`` ;了解其他 ``KERN_`` 值;syslog将这些值 解释为级别。特殊用法:打å°IP地å€ä½¿ç”¨:: __be32 ipaddress; printk(KERN_INFO "my ip: %pI4\n", &ipaddress); :c:func:`printk()` 内部使用的1K缓冲区,ä¸æ•èŽ·æº¢å‡ºã€‚请确ä¿è¶³å¤Ÿä½¿ç”¨ã€‚ .. note:: 当您开始在用户程åºä¸å°†printf打æˆprintk时,就知é“自己是真æ£çš„å†…æ ¸ç¨‹åºå‘˜äº† :) .. note:: å¦ä¸€ä¸ªæ³¨é‡Šï¼šæœ€åˆçš„unix第å…版æºä»£ç 在其printf函数的顶部有一个注释:“printf ä¸åº”该用于å½å½å–³å–³â€ã€‚ä½ ä¹Ÿåº”è¯¥éµå¾ªæ¤å»ºè®®ã€‚ :c:func:`copy_to_user()` / :c:func:`copy_from_user()` / :c:func:`get_user()` / :c:func:`put_user()` --------------------------------------------------------------------------------------------------- 定义于 ``include/linux/uaccess.h`` / ``asm/uaccess.h`` **[ç¡çœ ]** :c:func:`put_user()` å’Œ :c:func:`get_user()` 用于从用户空间ä¸èŽ·å–å’Œå‘用户空 é—´ä¸ä¼ 出å•ä¸ªå€¼ï¼ˆå¦‚intã€char或long)。指å‘用户空间的指针永远ä¸åº”该直接å–消 引用:应该使用这些程åºå¤åˆ¶æ•°æ®ã€‚两者都返回 ``-EFAULT`` 或 0。 :c:func:`copy_to_user()` å’Œ :c:func:`copy_from_user()` 更通用:它们从/å‘用户 空间å¤åˆ¶ä»»æ„æ•°é‡çš„æ•°æ®ã€‚ .. warning:: 与 :c:func:`put_user()` å’Œ :c:func:`get_user()` ä¸åŒï¼Œå®ƒä»¬è¿”回未å¤åˆ¶çš„ æ•°æ®é‡ï¼ˆå³0ä»ç„¶æ„味ç€æˆåŠŸï¼‰ã€‚ ã€æ˜¯çš„ï¼Œè¿™ä¸ªæ„šè ¢çš„æŽ¥å£çœŸå¿ƒè®©æˆ‘尴尬。ç«çˆ†çš„å£æ°´ä»—大概æ¯å¹´éƒ½ä¼šå‘生。 —— Rusty Russell】 这些函数å¯ä»¥éšå¼ç¡çœ 。它ä¸åº”该在用户上下文之外调用(没有æ„义)ã€è°ƒç”¨æ—¶ç¦ç”¨ä¸æ– 或获得自旋é”。 :c:func:`kmalloc()`/:c:func:`kfree()` ------------------------------------- 定义于 ``include/linux/slab.h`` **[å¯èƒ½ç¡çœ :è§ä¸‹]** 这些函数用于动æ€è¯·æ±‚指针对é½çš„内å˜å—,类似用户空间ä¸çš„mallocå’Œfree,但 :c:func:`kmalloc()` 需è¦é¢å¤–çš„æ ‡å¿—è¯ã€‚é‡è¦çš„值: ``GFP_KERNEL`` å¯ä»¥ç¡çœ 和交æ¢ä»¥é‡Šæ”¾å†…å˜ã€‚åªå…许在用户上下文ä¸ä½¿ç”¨ï¼Œä½†è¿™æ˜¯åˆ†é…内å˜æœ€å¯é 的方法。 ``GFP_ATOMIC`` ä¸ä¼šç¡çœ 。较 ``GFP_KERNEL`` æ›´ä¸å¯é ,但å¯ä»¥ä»Žä¸æ–ä¸Šä¸‹æ–‡è°ƒç”¨ã€‚ä½ **应该** 有一个很好的内å˜ä¸è¶³é”™è¯¯å¤„ç†ç–略。 ``GFP_DMA`` 分é…低于16MBçš„ISA DMAã€‚å¦‚æžœä½ ä¸çŸ¥é“é‚£æ˜¯ä»€ä¹ˆï¼Œé‚£ä½ å°±ä¸éœ€è¦äº†ã€‚éžå¸¸ä¸å¯é 。 å¦‚æžœæ‚¨çœ‹åˆ°ä¸€ä¸ªä»Žæ— æ•ˆä¸Šä¸‹æ–‡è¦å‘Šæ¶ˆæ¯è°ƒç”¨çš„ç¡çœ 的函数,那么您å¯èƒ½åœ¨æ²¡æœ‰ ``GFP_ATOMIC`` 的情况下从ä¸æ–上下文调用了一个ç¡çœ 的分é…å‡½æ•°ã€‚ä½ å¿…é¡»ç«‹å³ä¿®å¤ï¼Œ å¿«ç‚¹ï¼ å¦‚æžœä½ è¦åˆ†é…至少 ``PAGE_SIZE`` ( ``asm/page.h`` 或 ``asm/page_types.h`` ) å—节,请考虑使用 :c:func:`__get_free_pages()` ( ``include/linux/gfp.h`` )。 它采用顺åºå‚数(0表示页é¢å¤§å°ï¼Œ1表示åŒé¡µï¼Œ2表示四页……)和与上述相åŒçš„å†…å˜ ä¼˜å…ˆçº§æ ‡å¿—å—。 如果分é…çš„å—节数超过一页,å¯ä»¥ä½¿ç”¨ :c:func:`vmalloc()` ã€‚å®ƒå°†åœ¨å†…æ ¸æ˜ å°„ä¸åˆ† é…虚拟内å˜ã€‚æ¤å—在物ç†å†…å˜ä¸ä¸æ˜¯è¿žç»çš„,但是MMU(内å˜ç®¡ç†å•å…ƒï¼‰ä½¿å®ƒçœ‹èµ·æ¥åƒ 是为您准备好的连ç»ç©ºé—´ï¼ˆå› æ¤å®ƒåªæ˜¯çœ‹èµ·æ¥å¯¹cpuè¿žç»ï¼Œå¯¹å¤–部设备驱动程åºåˆ™ä¸ç„¶ï¼‰ã€‚ 如果您真的需è¦ä¸ºä¸€äº›å¥‡æ€ªçš„设备æ供大é‡ç‰©ç†ä¸Šè¿žç»çš„内å˜ï¼Œé‚£ä¹ˆæ‚¨å°±ä¼šé‡åˆ°é—®é¢˜ï¼š Linux对æ¤æ”¯æŒå¾ˆå·®ï¼Œå› 为æ£åœ¨è¿è¡Œçš„å†…æ ¸ä¸çš„内å˜ç¢Žç‰‡åŒ–会使它å˜å¾—很困难。最好的 方法是在引导过程的早期通过 :c:func:`alloc_bootmem()` 函数分é…。 在创建自己的常用对象缓å˜ä¹‹å‰ï¼Œè¯·è€ƒè™‘使用 ``include/linux/slab.h`` ä¸çš„slab 缓å˜ã€‚ :c:macro:`current` ------------------ 定义于 ``include/asm/current.h`` æ¤å…¨å±€å˜é‡ï¼ˆå…¶å®žæ˜¯å®ï¼‰åŒ…å«æŒ‡å‘当å‰ä»»åŠ¡ç»“构(task structureï¼‰çš„æŒ‡é’ˆï¼Œå› æ¤ä»…在 用户上下文ä¸æœ‰æ•ˆã€‚例如,当进程进行系统调用时,这将指å‘调用进程的任务结构。 在ä¸æ–上下文ä¸ä¸ä¸ºç©ºï¼ˆ**not NULL**)。 :c:func:`mdelay()`/:c:func:`udelay()` ------------------------------------- 定义于 ``include/asm/delay.h`` / ``include/linux/delay.h`` :c:func:`udelay()` å’Œ :c:func:`ndelay()` 函数å¯è¢«ç”¨äºŽå°æš‚åœã€‚ä¸è¦å¯¹å®ƒä»¬ä½¿ç”¨ å¤§çš„å€¼ï¼Œå› ä¸ºè¿™æ ·ä¼šå¯¼è‡´æº¢å‡ºâ€”â€”å¸®åŠ©å‡½æ•° :c:func:`mdelay()` 在这里很有用,或者 考虑 :c:func:`msleep()`。 :c:func:`cpu_to_be32()`/:c:func:`be32_to_cpu()`/:c:func:`cpu_to_le32()`/:c:func:`le32_to_cpu()` ----------------------------------------------------------------------------------------------- 定义于 ``include/asm/byteorder.h`` :c:func:`cpu_to_be32()` 系列函数(其ä¸â€œ32â€å¯ä»¥æ›¿æ¢ä¸º64或16,“beâ€å¯ä»¥æ›¿æ¢ä¸º “leâ€ï¼‰æ˜¯åœ¨å†…æ ¸ä¸è¿›è¡Œå—节åºè½¬æ¢çš„常用方法:它们返回转æ¢åŽçš„值。所有的å˜ä½“也 æä¾›åå‘转æ¢å‡½æ•°ï¼š :c:func:`be32_to_cpu()` ç‰ã€‚ 这些函数有两个主è¦çš„å˜ä½“:指针å˜ä½“,例如 :c:func:`cpu_to_be32p()` ï¼Œå®ƒèŽ·å– æŒ‡å‘给定类型的指针,并返回转æ¢åŽçš„值。å¦ä¸€ä¸ªå˜ä½“是“in-situâ€ç³»åˆ—,例如 :c:func:`cpu_to_be32s()` ,它转æ¢æŒ‡é’ˆå¼•ç”¨çš„值,并返回void。 :c:func:`local_irq_save()`/:c:func:`local_irq_restore()` -------------------------------------------------------- 定义于 ``include/linux/irqflags.h`` 这些程åºç¦ç”¨æœ¬åœ°CPU上的硬ä¸æ–,并还原它们。它们是å¯é‡å…¥çš„;在其一个 ``unsigned long flags`` å‚æ•°ä¸ä¿å˜ä»¥å‰çš„状æ€ã€‚如果您知é“ä¸æ–å·²å¯ç”¨ï¼Œé‚£ä¹ˆå¯ 直接使用 :c:func:`local_irq_disable()` å’Œ :c:func:`local_irq_enable()`。 .. _local_bh_disable_zh: :c:func:`local_bh_disable()`/:c:func:`local_bh_enable()` -------------------------------------------------------- 定义于 ``include/linux/bottom_half.h`` 这些程åºç¦ç”¨æœ¬åœ°CPU上的软ä¸æ–,并还原它们。它们是å¯é‡å…¥çš„;如果之å‰ç¦ç”¨äº† 软ä¸æ–,那么在调用这对函数之åŽä»ç„¶ä¼šç¦ç”¨å®ƒä»¬ã€‚它们阻æ¢è½¯ä¸æ–å’Œåä»»åŠ¡åœ¨å½“å‰ CPU上è¿è¡Œã€‚ :c:func:`smp_processor_id()` ---------------------------- 定义于 ``include/linux/smp.h`` :c:func:`get_cpu()` ç¦ç”¨æŠ¢å ï¼ˆè¿™æ ·æ‚¨å°±ä¸ä¼šçªç„¶ç§»åŠ¨åˆ°å¦ä¸€ä¸ªcpuï¼‰å¹¶è¿”å›žå½“å‰ å¤„ç†å™¨å·ï¼Œä»‹äºŽ0å’Œ ``NR_CPUS`` 之间。请注æ„,CPUç¼–å·ä¸ä¸€å®šæ˜¯è¿žç»çš„。完æˆåŽï¼Œ 使用 :c:func:`put_cpu()` å†æ¬¡è¿”回。 如果您知é“您ä¸èƒ½è¢«å¦ä¸€ä¸ªä»»åŠ¡æŠ¢å (å³æ‚¨å¤„于ä¸æ–上下文ä¸ï¼Œæˆ–å·²ç¦ç”¨æŠ¢å ),您 å¯ä»¥ä½¿ç”¨ :c:func:`smp_processor_id()`。 ``__init``/``__exit``/``__initdata`` ------------------------------------ 定义于 ``include/linux/init.h`` 引导之åŽï¼Œå†…æ ¸é‡Šæ”¾ä¸€ä¸ªç‰¹æ®Šçš„éƒ¨åˆ†ï¼›ç”¨ ``__init`` æ ‡è®°çš„å‡½æ•°å’Œç”¨ ``__initdata`` æ ‡è®°çš„æ•°æ®ç»“构在引导完æˆåŽè¢«ä¸¢å¼ƒï¼šåŒæ ·åœ°ï¼Œæ¨¡å—在åˆå§‹åŒ–åŽä¸¢å¼ƒæ¤å†…å˜ã€‚ ``__exit`` 用于声明åªåœ¨é€€å‡ºæ—¶éœ€è¦çš„函数:如果æ¤æ–‡ä»¶æœªç¼–译为模å—,则该函数将 è¢«åˆ é™¤ã€‚è¯·å‚阅头文件以使用。请注æ„,使用 :c:func:`EXPORT_SYMBOL()` 或 :c:func:`EXPORT_SYMBOL_GPL()` å°†æ ‡è®°ä¸º ``__init`` 的函数导出到模å—是没有æ„义 的——这将出问题。 :c:func:`__initcall()`/:c:func:`module_init()` ---------------------------------------------- 定义于 ``include/linux/init.h`` / ``include/linux/module.h`` å†…æ ¸çš„è®¸å¤šéƒ¨åˆ†éƒ½ä½œä¸ºæ¨¡å—ï¼ˆå†…æ ¸çš„å¯åŠ¨æ€åŠ 载部分)良好æœåŠ¡ã€‚使用 :c:func:`module_init()` å’Œ :c:func:`module_exit()` å®å¯ä»¥ç®€åŒ–代ç ç¼–å†™ï¼Œæ— éœ€ ``#ifdef`` ,å³å¯ä»¥ä½œä¸ºæ¨¡å—è¿è¡Œæˆ–å†…ç½®åœ¨å†…æ ¸ä¸ã€‚ :c:func:`module_init()` å®å®šä¹‰åœ¨æ¨¡å—æ’入时(如果文件编译为模å—)或在引导时 调用哪个函数:如果文件未编译为模å—,:c:func:`module_init()` å®å°†ç‰æ•ˆäºŽ :c:func:`__initcall()` ,它通过链接器的é”力确ä¿åœ¨å¼•å¯¼æ—¶è°ƒç”¨è¯¥å‡½æ•°ã€‚ 该函数å¯ä»¥è¿”回一个错误值,以导致模å—åŠ è½½å¤±è´¥ï¼ˆä¸å¹¸çš„是,如果将模å—ç¼–è¯‘åˆ°å†…æ ¸ ä¸ï¼Œåˆ™æ¤æ“ä½œæ— æ•ˆï¼‰ã€‚æ¤å‡½æ•°åœ¨å¯ç”¨ä¸æ–的用户上下文ä¸è°ƒç”¨ï¼Œå› æ¤å¯ä»¥ç¡çœ 。 :c:func:`module_exit()` ----------------------- 定义于 ``include/linux/module.h`` 这个å®å®šä¹‰äº†åœ¨æ¨¡å—åˆ é™¤æ—¶è¦è°ƒç”¨çš„å‡½æ•°ï¼ˆå¦‚æžœæ˜¯ç¼–è¯‘åˆ°å†…æ ¸ä¸çš„æ–‡ä»¶ï¼Œåˆ™æ— ç”¨æ¦ä¹‹åœ°ï¼‰ã€‚ åªæœ‰åœ¨æ¨¡å—使用计数到零时æ‰ä¼šè°ƒç”¨å®ƒã€‚这个函数也å¯ä»¥ç¡çœ ,但ä¸èƒ½å¤±è´¥ï¼šå½“它返回 时,所有的东西都必须清ç†å¹²å‡€ã€‚ 注æ„,这个å®æ˜¯å¯é€‰çš„:如果它ä¸å˜åœ¨ï¼Œæ‚¨çš„模å—å°†ä¸å¯ç§»é™¤ï¼ˆé™¤éž ``rmmod -f`` )。 :c:func:`try_module_get()`/:c:func:`module_put()` ------------------------------------------------- 定义于 ``include/linux/module.h`` 这些函数会æ“作模å—使用计数,以防æ¢åˆ 除(如果å¦ä¸€ä¸ªæ¨¡å—使用其导出的符å·ä¹‹ä¸€ï¼Œ åˆ™æ— æ³•åˆ é™¤æ¨¡å—,å‚è§ä¸‹æ–‡ï¼‰ã€‚在调用模å—代ç 之å‰ï¼Œæ‚¨åº”该在该模å—上调用 :c:func:`try_module_get()` :若失败,那么该模å—å°†è¢«åˆ é™¤ï¼Œæ‚¨åº”è¯¥å°†å…¶è§†ä¸ºä¸å˜åœ¨ã€‚ è‹¥æˆåŠŸï¼Œæ‚¨å°±å¯ä»¥å®‰å…¨åœ°è¿›å…¥æ¨¡å—,并在完æˆåŽè°ƒç”¨æ¨¡å— :c:func:`module_put()` 。 大多数å¯æ³¨å†Œç»“构体都有所有者å—段,例如在 :c:type:`struct file_operations <file_operations>` 结构体ä¸ï¼Œæ¤å—段应设置为 å® ``THIS_MODULE`` 。 ç‰å¾…队列 ``include/linux/wait.h`` ==================================== **[ç¡çœ ]** ç‰å¾…队列用于ç‰å¾…æŸç¨‹åºåœ¨æ¡ä»¶ä¸ºçœŸæ—¶å”¤é†’å¦ä¸€ç¨‹åºã€‚å¿…é¡»å°å¿ƒä½¿ç”¨ï¼Œä»¥ç¡®ä¿æ²¡æœ‰ç«žäº‰ æ¡ä»¶ã€‚先声明一个 :c:type:`wait_queue_head_t` ,然åŽå¯¹å¸Œæœ›ç‰å¾…该æ¡ä»¶çš„进程声明 一个关于它们自己的 :c:type:`wait_queue_entry_t` ,并将其放入队列ä¸ã€‚ 声明 ----- 使用 :c:func:`DECLARE_WAIT_QUEUE_HEAD()` å®å£°æ˜Žä¸€ä¸ª ``wait_queue_head_t`` , 或者在åˆå§‹åŒ–代ç ä¸ä½¿ç”¨ :c:func:`init_waitqueue_head()` 程åºã€‚ 排队 ----- 将自己放在ç‰å¾…队列ä¸ç›¸å½“å¤æ‚ï¼Œå› ä¸ºä½ å¿…é¡»åœ¨æ£€æŸ¥æ¡ä»¶ä¹‹å‰å°†è‡ªå·±æ”¾å…¥é˜Ÿåˆ—ä¸ã€‚有一 个å®å¯ä»¥æ¥æ‰§è¡Œæ¤æ“作: :c:func:`wait_event_interruptible()` ( ``include/linux/wait.h`` )第一个å‚数是ç‰å¾…队列头,第二个å‚数是计算的表达 å¼ï¼›å½“该表达å¼ä¸ºtrueæ—¶å®è¿”回0,或者在接收到信å·æ—¶è¿”回 ``-ERESTARTSYS`` 。 :c:func:`wait_event()` 版本会忽略信å·ã€‚ 唤醒排队任务 ------------- 调用 :c:func:`wake_up()` ( ``include/linux/wait.h`` ),它将唤醒队列ä¸çš„所有 进程。例外情况:如果有一个进程设置了 ``TASK_EXCLUSIVE`` ï¼Œé˜Ÿåˆ—çš„å…¶ä½™éƒ¨åˆ†å°†ä¸ ä¼šè¢«å”¤é†’ã€‚è¿™ä¸ªåŸºæœ¬å‡½æ•°çš„å…¶ä»–å˜ä½“也å¯ä»¥åœ¨åŒä¸€ä¸ªå¤´æ–‡ä»¶ä¸ä½¿ç”¨ã€‚ 原åæ“作 ========= æŸäº›æ“作在所有平å°ä¸Šéƒ½æœ‰ä¿è¯ã€‚第一类为æ“作 :c:type:`atomic_t` ( ``include/asm/atomic.h`` )的函数;它包å«ä¸€ä¸ªæœ‰ç¬¦å·æ•´æ•°ï¼ˆè‡³å°‘32ä½é•¿ï¼‰ï¼Œ 您必须使用这些函数æ¥æ“ä½œæˆ–è¯»å– :c:type:`atomic_t` å˜é‡ã€‚ :c:func:`atomic_read()` å’Œ :c:func:`atomic_set()` 获å–并设置计数器,还有 :c:func:`atomic_add()` ,:c:func:`atomic_sub()` ,:c:func:`atomic_inc()` , :c:func:`atomic_dec()` å’Œ :c:func:`atomic_dec_and_test()` (如果递å‡ä¸ºé›¶ï¼Œ 则返回true)。 是的。它在原åå˜é‡ä¸ºé›¶æ—¶è¿”回true(å³!=0)。 请注æ„,这些函数比普通的算术è¿ç®—é€Ÿåº¦æ…¢ï¼Œå› æ¤ä¸åº”过度使用。 第二类原åæ“作是在 ``unsigned long`` ( ``include/linux/bitops.h`` )上的 原åä½æ“作。这些æ“作通常采用指å‘ä½æ¨¡å¼ï¼ˆbit pattern)的指针,第0ä½æ˜¯æœ€ä½Žæœ‰æ•ˆ ä½ã€‚:c:func:`set_bit()`,:c:func:`clear_bit()` å’Œ :c:func:`change_bit()` 设置〠清除和更改给定ä½ã€‚:c:func:`test_and_set_bit()` ,:c:func:`test_and_clear_bit()` å’Œ :c:func:`test_and_change_bit()` 执行相åŒçš„æ“作,但如果之å‰è®¾ç½®äº†ä½ï¼Œåˆ™è¿”回 true;这些对于原åè®¾ç½®æ ‡å¿—ç‰¹åˆ«æœ‰ç”¨ã€‚ å¯ä»¥ä½¿ç”¨å¤§äºŽ ``BITS_PER_LONG`` ä½çš„ä½ç´¢å¼•è°ƒç”¨è¿™äº›æ“作。但结果在大端åºå¹³å°ä¸Š ä¸å¤ªæ£å¸¸ï¼Œæ‰€ä»¥æœ€å¥½ä¸è¦è¿™æ ·åšã€‚ ç¬¦å· ===== åœ¨å†…æ ¸å†…éƒ¨ï¼Œæ£å¸¸çš„链接规则ä»ç„¶é€‚用(å³é™¤éžç”¨static关键å—将符å·å£°æ˜Žä¸ºæ–‡ä»¶èŒƒå›´ï¼Œ å¦åˆ™å®ƒå¯ä»¥åœ¨å†…æ ¸ä¸çš„任何ä½ç½®ä½¿ç”¨ï¼‰ã€‚但是对于模å—,会ä¿ç•™ä¸€ä¸ªç‰¹æ®Šå¯å¯¼å‡ºç¬¦å·è¡¨ï¼Œ 该表将入å£ç‚¹é™åˆ¶ä¸ºå†…æ ¸å†…éƒ¨ã€‚æ¨¡å—也å¯ä»¥å¯¼å‡ºç¬¦å·ã€‚ :c:func:`EXPORT_SYMBOL()` ------------------------- 定义于 ``include/linux/export.h`` 这是导出符å·çš„ç»å…¸æ–¹æ³•ï¼šåŠ¨æ€åŠ 载的模å—将能够æ£å¸¸ä½¿ç”¨ç¬¦å·ã€‚ :c:func:`EXPORT_SYMBOL_GPL()` ----------------------------- 定义于 ``include/linux/export.h`` 类似于 :c:func:`EXPORT_SYMBOL()`,åªæ˜¯ :c:func:`EXPORT_SYMBOL_GPL()` 导出的 符å·åªèƒ½ç”±å…·æœ‰ç”± :c:func:`MODULE_LICENSE()` 指定GPL兼容许å¯è¯çš„模å—看到。这 æ„味ç€æ¤å‡½æ•°è¢«è®¤ä¸ºæ˜¯ä¸€ä¸ªå†…部实现问题,而ä¸æ˜¯ä¸€ä¸ªçœŸæ£çš„接å£ã€‚一些维护人员和 å¼€å‘äººå‘˜åœ¨æ·»åŠ ä¸€äº›æ–°çš„API或功能时å¯èƒ½å´éœ€è¦å¯¼å‡º EXPORT_SYMBOL_GPL()。 :c:func:`EXPORT_SYMBOL_NS()` ---------------------------- 定义于 ``include/linux/export.h`` 这是 ``EXPORT_SYMBOL()`` çš„å˜ä½“,å…许指定符å·å‘½å空间。符å·å称空间记录于 Documentation/core-api/symbol-namespaces.rst 。 :c:func:`EXPORT_SYMBOL_NS_GPL()` -------------------------------- 定义于 ``include/linux/export.h`` 这是 ``EXPORT_SYMBOL_GPL()`` çš„å˜ä½“,å…许指定符å·å‘½å空间。符å·å称空间记录于 Documentation/core-api/symbol-namespaces.rst 。 程åºä¸Žæƒ¯ä¾‹ =========== åŒå‘链表 ``include/linux/list.h`` ----------------------------------- å†…æ ¸å¤´æ–‡ä»¶ä¸æ›¾ç»æœ‰ä¸‰ç»„链表程åºï¼Œä½†è¿™ä¸€ç»„æ˜¯èµ¢å®¶ã€‚å¦‚æžœä½ å¯¹ä¸€ä¸ªå•é“¾è¡¨æ²¡æœ‰ç‰¹åˆ«è¿«åˆ‡çš„ 需求,那么这是一个ä¸é”™çš„选择。 通常 :c:func:`list_for_each_entry()` 很有用。 返回值惯例 ------------ 对于在用户上下文ä¸è°ƒç”¨çš„代ç ,è¿èƒŒCè¯è¨€æƒ¯ä¾‹æ˜¯å¾ˆå¸¸è§çš„,å³è¿”回0表示æˆåŠŸï¼Œè¿”回 负错误值(例如 ``-EFAULT`` )表示失败。这在一开始å¯èƒ½æ˜¯ä¸ç›´è§‚çš„ï¼Œä½†åœ¨å†…æ ¸ä¸ ç›¸å½“æ™®é。 使用 :c:func:`ERR_PTR()` ( ``include/linux/err.h`` )将负错误值编ç 到指针ä¸ï¼Œ 然åŽä½¿ç”¨ :c:func:`IS_ERR()` å’Œ :c:func:`PTR_ERR()` 将其å†å–出:é¿å…为错误值 使用å•ç‹¬çš„指针å‚数。挺讨厌的,但的确是个好方å¼ã€‚ ç ´å编译 ---------- Linus和其他开å‘人员有时会更改开å‘å†…æ ¸ä¸çš„函数或结构体åç§°ï¼›è¿™æ ·åšä¸ä»…是为了 让æ¯ä¸ªäººéƒ½ä¿æŒè¦æƒ•ï¼Œè¿˜åæ˜ äº†ä¸€ä¸ªé‡å¤§çš„更改(例如,ä¸èƒ½å†åœ¨æ‰“å¼€ä¸æ–的情况下 调用,或者执行é¢å¤–的检查,或者ä¸æ‰§è¡Œä»¥å‰æ•èŽ·çš„检查)。通常这会附带一个linux å†…æ ¸é‚®ä»¶åˆ—è¡¨ä¸ç›¸å½“å…¨é¢çš„注释;请æœç´¢å˜æ¡£ä»¥æŸ¥çœ‹ã€‚简å•åœ°å¯¹æ–‡ä»¶è¿›è¡Œå…¨å±€æ›¿æ¢é€šå¸¸ 会让事情å˜å¾— **更糟** 。 åˆå§‹åŒ–结构体æˆå‘˜ ------------------ åˆå§‹åŒ–结构体的首选方法是使用指定的åˆå§‹åŒ–器,如ISO C99所述。 例如:: static struct block_device_operations opt_fops = { .open = opt_open, .release = opt_release, .ioctl = opt_ioctl, .check_media_change = opt_media_change, }; 这使得很容易查找(grep),并且å¯ä»¥æ¸…楚地看到设置了哪些结构å—æ®µã€‚ä½ åº”è¯¥è¿™æ ·åšï¼Œ å› ä¸ºå®ƒçœ‹èµ·æ¥å¾ˆé…·ã€‚ GNU 扩展 ---------- Linuxå†…æ ¸ä¸æ˜Žç¡®å…许GNU扩展。请注æ„,由于缺ä¹é€šç”¨æ€§ï¼Œä¸€äº›æ›´å¤æ‚的版本并没有 得到很好的支æŒï¼Œä½†ä»¥ä¸‹å†…å®¹è¢«è®¤ä¸ºæ˜¯æ ‡å‡†çš„ï¼ˆæœ‰å…³æ›´å¤šè¯¦ç»†ä¿¡æ¯ï¼Œè¯·å‚阅GCC info页 的“C 扩展â€éƒ¨åˆ†â€”—是的,实际上是info页,手册页åªæ˜¯infoä¸å†…容的简çŸæ‘˜è¦ï¼‰ã€‚ - 内è”函数 - è¯å¥è¡¨è¾¾å¼ï¼ˆStatement expressions)(å³ï¼ˆ{ å’Œ })结构)。 - 声明函数/å˜é‡/类型的属性(__attribute__) - typeof - 零长度数组 - å®å˜é‡ - 空指针è¿ç®— - éžå¸¸é‡ï¼ˆNon-Constant)åˆå§‹åŒ–ç¨‹åº - 汇编程åºæŒ‡ä»¤ï¼ˆåœ¨ arch/ å’Œ include/asm/ 之内) - å—符串函数å(__func__)。 - __builtin_constant_p() åœ¨å†…æ ¸ä¸ä½¿ç”¨long longæ—¶è¦å°å¿ƒï¼Œgcc为其生æˆçš„代ç éžå¸¸ç³Ÿç³•ï¼šé™¤æ³•å’Œä¹˜æ³•åœ¨i386上 ä¸èƒ½å·¥ä½œï¼Œå› ä¸ºå†…æ ¸çŽ¯å¢ƒä¸ç¼ºå°‘用于它的gccè¿è¡Œæ—¶å‡½æ•°ã€‚ C++ --- åœ¨å†…æ ¸ä¸ä½¿ç”¨C++通常是个å主æ„ï¼Œå› ä¸ºå†…æ ¸ä¸æ供必è¦çš„è¿è¡Œæ—¶çŽ¯å¢ƒï¼Œå¹¶ä¸”ä¸ä¸ºå…¶ 测试包å«æ–‡ä»¶ã€‚ä¸è¿‡è¿™ä»ç„¶æ˜¯å¯èƒ½çš„,但ä¸å»ºè®®ã€‚å¦‚æžœä½ çœŸçš„æƒ³è¿™ä¹ˆåšï¼Œè‡³å°‘别用 异常处ç†ï¼ˆexceptions)。 #if --- 通常认为,在头文件(或.c文件顶部)ä¸ä½¿ç”¨å®æ¥æŠ½è±¡å‡½æ•°æ¯”在æºä»£ç ä¸ä½¿ç”¨â€œifâ€é¢„ 处ç†å™¨è¯å¥æ›´å¹²å‡€ã€‚ æŠŠä½ çš„ä¸œè¥¿æ”¾è¿›å†…æ ¸é‡Œ ====================== ä¸ºäº†è®©ä½ çš„ä¸œè¥¿æ›´æ£å¼ã€è¡¥ä¸æ›´æ•´æ´ï¼Œè¿˜æœ‰ä¸€äº›å·¥ä½œè¦åšï¼š - æžæ¸…æ¥šä½ åœ¨è°çš„地界儿上干活。查看æºæ–‡ä»¶çš„顶部〠``MAINTAINERS`` æ–‡ä»¶ä»¥åŠ ``CREDITS`` 文件的最åŽä¸€éƒ¨åˆ†ã€‚ä½ åº”è¯¥å’Œæ¤äººå调,确ä¿ä½ 没有é‡æ–°å‘明轮å, 或者å°è¯•ä¸€äº›å·²ç»è¢«æ‹’ç»çš„东西。 ç¡®ä¿ä½ æŠŠä½ çš„åå—和电å邮件地å€æ”¾åœ¨ä½ åˆ›å»ºæˆ–ä¿®æ”¹çš„ä»»ä½•æ–‡ä»¶çš„é¡¶éƒ¨ã€‚å½“äººä»¬å‘ çŽ°ä¸€ä¸ªç¼ºé™·ï¼Œæˆ–è€…æƒ³è¦åšå‡ºä¿®æ”¹æ—¶ï¼Œè¿™æ˜¯ä»–们首先会看的地方。 - é€šå¸¸ä½ éœ€è¦ä¸€ä¸ªé…置选项æ¥æ”¯æŒä½ çš„å†…æ ¸ç¼–ç¨‹ã€‚åœ¨é€‚å½“çš„ç›®å½•ä¸ç¼–辑 ``Kconfig`` 。 é…ç½®è¯è¨€å¾ˆå®¹æ˜“通过剪切和粘贴æ¥ä½¿ç”¨ï¼Œåœ¨ Documentation/kbuild/kconfig-language.rst ä¸æœ‰å®Œæ•´çš„文档。 在您对选项的æè¿°ä¸ï¼Œè¯·ç¡®ä¿åŒæ—¶ç…§é¡¾åˆ°äº†ä¸“家用户和对æ¤åŠŸèƒ½ä¸€æ— 所知的用户。 在æ¤è¯´æ˜Žä»»ä½•ä¸å…¼å®¹å’Œé—®é¢˜ã€‚结尾一定è¦å†™ä¸Šâ€œå¦‚有疑问,就选Nâ€ï¼ˆæˆ–者是“Yâ€ï¼‰ï¼› 这是针对那些看ä¸æ‡‚ä½ åœ¨è¯´ä»€ä¹ˆçš„äººçš„ã€‚ - 编辑 ``Makefile`` :é…ç½®å˜é‡åœ¨è¿™é‡Œå¯¼å‡ºï¼Œå› æ¤é€šå¸¸ä½ åªéœ€æ·»åŠ 一行 “obj-$(CONFIG_xxx) += xxx.oâ€ã€‚è¯æ³•è®°å½•åœ¨ Documentation/kbuild/makefiles.rst 。 - å¦‚æžœä½ åšäº†ä¸€äº›æœ‰æ„义的事情,那å¯ä»¥æŠŠè‡ªå·±æ”¾è¿› ``CREDITS`` ,通常ä¸æ¢ä¸€ä¸ª æ–‡ä»¶ï¼ˆæ— è®ºå¦‚ä½•ä½ çš„åå—都应该在æºæ–‡ä»¶çš„顶部)。维护人员æ„味ç€æ‚¨å¸Œæœ›åœ¨å¯¹ å系统进行更改时得到询问,并了解缺陷;这æ„味ç€å¯¹æŸéƒ¨åˆ†ä»£ç åšå‡ºæ›´å¤šæ‰¿è¯ºã€‚ - 最åŽï¼Œåˆ«å¿˜è®°åŽ»é˜…读 Documentation/process/submitting-patches.rst , 也许还有 Documentation/process/submitting-drivers.rst 。 Kernel 仙女棒 =============== æµè§ˆæºä»£ç 时的一些收è—。请éšæ„æ·»åŠ åˆ°æ¤åˆ—表。 ``arch/x86/include/asm/delay.h``:: #define ndelay(n) (__builtin_constant_p(n) ? \ ((n) > 20000 ? __bad_ndelay() : __const_udelay((n) * 5ul)) : \ __ndelay(n)) ``include/linux/fs.h``:: /* * Kernel pointers have redundant information, so we can use a * scheme where we can return either an error code or a dentry * pointer with the same return value. * * This should be a per-architecture thing, to allow different * error and pointer decisions. */ #define ERR_PTR(err) ((void *)((long)(err))) #define PTR_ERR(ptr) ((long)(ptr)) #define IS_ERR(ptr) ((unsigned long)(ptr) > (unsigned long)(-1000)) ``arch/x86/include/asm/uaccess_32.h:``:: #define copy_to_user(to,from,n) \ (__builtin_constant_p(n) ? \ __constant_copy_to_user((to),(from),(n)) : \ __generic_copy_to_user((to),(from),(n))) ``arch/sparc/kernel/head.S:``:: /* * Sun people can't spell worth damn. "compatibility" indeed. * At least we *know* we can't spell, and use a spell-checker. */ /* Uh, actually Linus it is I who cannot spell. Too much murky * Sparc assembly will do this to ya. */ C_LABEL(cputypvar): .asciz "compatibility" /* Tested on SS-5, SS-10. Probably someone at Sun applied a spell-checker. */ .align 4 C_LABEL(cputypvar_sun4m): .asciz "compatible" ``arch/sparc/lib/checksum.S:``:: /* Sun, you just can't beat me, you just can't. Stop trying, * give up. I'm serious, I am going to kick the living shit * out of you, game over, lights out. */ 致谢 ===== æ„Ÿè°¢Andi Kleenæ出点å,回ç”æˆ‘çš„é—®é¢˜ï¼Œçº æ£æˆ‘的错误,充实内容ç‰å¸®åŠ©ã€‚ æ„Ÿè°¢Philipp Rumpfåšäº†è®¸å¤šæ‹¼å†™å’Œæ¸…晰度修å¤ï¼Œä»¥åŠä¸€äº›ä¼˜ç§€çš„ä¸æ˜Žæ˜¾çš„点。 æ„Ÿè°¢Werner Almesberger对 :c:func:`disable_irq()` åšäº†ä¸€ä¸ªå¾ˆå¥½çš„总结, Jes Sorensenå’ŒAndrea Arcangeli补充了一些注æ„事项。 æ„Ÿè°¢Michael Elizabeth Chastain检查并补充了é…置部分。 æ„Ÿè°¢Telsa Gwynne教我DocBook。