¡¶LinuxÄÚºËÇý¶¯Ä£¿é±à³ÌÖ¸ÄÏ¡·×î³õÊÇÓÉOri PomerantzΪ2.2°æ±¾µÄÄں˱àдµÄ £¬ºóÀ´£¬Ori½«ÎĵµÎ¬»¤µÄÈÎÎñ½»¸øÁËPeter Jay Salzman£¬PeterÍê³ÉÁË2.4Äں˰汾Îĵµ µÄ±àд£¬±Ï¾¹LinuxÄÚºËÇý¶¯Ä£¿éÊÇÒ»¸ö¸üкܿìµÄÄÚÈÝ¡£ÏÖÔÚ£¬PeterÒ²ÎÞ·¨ÌÚ³ö×ã¹»µÄ ʱ¼äÀ´Íê³É2.6Äں˰汾ÎĵµµÄ±àд£¬Ä¿Ç°¸Ã2.6Äں˰汾µÄÎĵµÓɺÏ×÷ÕßMichael Burian Íê³É¡£
°æ±¾ºÍ×¢Òâ
LinuxÄÚºËÄ£¿éÊÇÒ»¿é²»¶Ï¸üнø²½µÄÄÚÈÝ£¬ÔÚLKMPGÉÏ×ÜÓйØÓÚÊÇ·ñ±£Áô»¹ÊÇÀúÊ· °æ±¾µÄÕùÂÛ¡£MichaelºÍÎÒ×îÖÕÊǾö¶¨ÎªÃ¿¸öеÄÎȶ¨°æ±¾Äں˽¨Á¢Ò»¸öеÄÎĵµ·ÖÖ§¡£Ò² ¾ÍÊÇ˵LKMPG 2.4.xרעÓÚ2.4µÄÄںˣ¬¶øLKMPG 2.6.x½«×¨×¢ÓÚ2.6µÄÄںˡ£ÎÒÃDz»»áÔÚÒ» ƪÎĵµÖÐÌṩ¶Ô¾É°æ±¾Äں˵ÄÖ§³Ö£¬¶Ô´Ë¸ÐÐËȤµÄ¶ÁÕßÓ¦¸ÃÑ°ÕÒÏà¹Ø°æ±¾µÄÎĵµ·ÖÖ§¡£
ÔÚÎĵµÖеľø´ó²¿·ÖÔ´´úÂëºÍÌÖÂÛ¶¼Ó¦¸ÃÊÊÓÃÓÚÆäËüƽ̨£¬µ«ÎÒÎÞ·¨ÌṩÈκα£Ö¤¡£ÆäÖеÄÒ»¸öÀýÍâ¾ÍÊÇ Chapter 12, Öжϴ¦Àí¸ÃÕµÄÔ´´úÂëºÍÌÖÂÛ¾ÍÖ»ÊÊÓÃÓÚx86ƽ̨¡£
¸Ðл
¸ÐлÏÂÁÐÈËʿΪ´ËÎĵµÌṩÁËËûÃDZ¦¹óµÄÒâ¼û¡£ËûÃÇÊÇ£ºIgnacio Martin, David Porter, Daniele Paolo,Scarpazza ºÍ Dimo Velev¡£
ÒëÕß×¢
ÎÒ£¬ÒëÕߣ¬Ãû½ÐÌᄎ£¬Ä¿Ç°ÊÇÒ»ÃûÔÚ±±¾©Óʵç´óѧ¾Í¶ÁµÄͨÐÅרҵµÄ´óѧÉú¡£ ×Ô¸ßÖÐÆðÎÒ¾ÍÊÇLinuxµÄ°®ºÃÕß²¢×·ËæÖÁ½ñ¡£ÎÒϲ»¶Linux¸øÎÒ´øÀ´µÄ×ÔÓÉ£¬ÎÒÏë´ó¼ÒÒ²Ò»Ñù¡£Ã»ÓÐÈ˲»ÏòÍù×ÔÓÉ¡£
ÎÒѧϰÄÚºËÄ£¿é±àдʱ×î³õÔĶÁµÄÊÇOrelly³ö°æÉçµÄʹÓÃ2.0°æ±¾µÄÄں˵ÄÊé¼®£¬µ«ÈçͬÎÒÔ¤ÁϵÄÒ»Ñù£¬ ÊéÖеÄÐí¶àÊÂÀýÓÉÓÚÄں˴úÂëµÄ±ä»¯¶øÎÞ·¨Ê¹Óá£ÕâÈÃÏëÇ××ÔÌåÑéÄÚºËÄ£¿éµÄÉñÃصÄÎҷdz£¿àÄÕ¡£ ÎÒÔÚLinuxÎĵµ¼Æ»®ÔÚÉϺ£µÄ¾µÏñÕ¾ldp.linuxforum.netÉÏÕÒµ½ÁËÕâƪÎĵµ¡£
ÊÜÔ×÷ÕßOriµÄ¹ÄÀø£¬»ùÓÚÉÏ´ÎÍê³ÉµÄLKMPG 2.4µÄ£¬ÄÚÈÝÓÐÉÔÐíµÄ¸Ä±äºÍÀ©³ä¡£Ó¦¸ÃÊÇÄ¿Ç°×îеÄÁË¡£ ·ÒëµÄ·½Ê½ÓÐËù¸Ä±ä£¬ÔÚ»ùÓÚLDPÈϿɵÄdocbook¸ñʽÉÏ·Ò룬ͨ¹ýdocbook2htmlת»»Îª¸½¼þÖеÄhtmlÎĵµ¡£ ÓÉÓÚ¶Ôdocbook²»ÊǺÜÊìϤ£¬ÆäÖеÄһЩ±êÌâÉÐδ·Ò룬¶øÇÒ¿ÉÄÜÆÆ»µÁËÔÓеÄtag£¬µ¼ÖÂhtml³öÏÖһЩ´íÎóÏÔʾ£¬ µ«×ÜÌåÀ´ËµºÜÉÙ¡£ÐÞ¸ÄÁ˺ܶà2.4ÖеĴí±ð×Ö¡£
ѧϰ²¢·ÖÏíѧϰµÄ¹ý³ÌÊÇÎÒ·ÒëµÄ×îÖÕÄ¿µÄ¡£
Chapter 1. Introduction
Table of Contents
ʲôÊÇÄÚºËÄ£¿é£¿
ÄÚºËÄ£¿éÊÇÈçºÎ±»µ÷ÈëÄں˹¤×÷µÄ£¿
ʲôÊÇÄÚºËÄ£¿é£¿
ÏÖÔÚ£¬ÄãÊDz»ÊÇÏë±àдÄÚºËÄ£¿é¡£ÄãÓ¦¸Ã¶®µÃCÓïÑÔ£¬Ð´¹ýһЩÓû§³ÌÐò£¬ ÄÇôÏÖÔÚÄ㽫Ҫ¼ûʶһЩÕæʵµÄ¶«Î÷¡£ÔÚÕâÀÄã»á¿´µ½Ò»¸öÒ°ÂùµÄÖ¸ÕëÊÇÈçºÎ »ÙµôÄãµÄÎļþϵͳµÄ£¬Ò»´ÎÄں˱ÀÀ£Òâζ×ÅÖØÆô¶¯¡£
ʲôÊÇÄÚºËÄ£¿é£¿ÄÚºËÄ£¿éÊÇһЩ¿ÉÒÔÈòÙ×÷ϵͳÄÚºËÔÚÐèҪʱÔØÈëºÍÖ´ ÐеĴúÂ룬ÕâͬÑùÒâζ×ÅËü¿ÉÒÔÔÚ²»ÐèҪʱÓвÙ×÷ϵͳжÔØ¡£ËüÃÇÀ©Õ¹Á˲Ù×÷ϵ ͳÄں˵ŦÄÜÈ´²»ÐèÒªÖØÐÂÆô¶¯ÏµÍ³¡£¾ÙÀý×ÓÀ´Ëµ£¬ÆäÖÐÒ»ÖÖÄÚºËÄ£¿éʱÉ豸Çý ¶¯³ÌÐòÄ£¿é£¬ËüÃÇÓÃÀ´ÈòÙ×÷ϵͳÕýȷʶ±ð£¬Ê¹Óð²×°ÔÚϵͳÉϵÄÓ²¼þÉ豸¡£Èç ¹ûûÓÐÄÚºËÄ£¿é£¬ÎÒÃDz»µÃ²»Ò»´ÎÓÖÒ»´ÎÖØбàÒëÉú³Éµ¥Äں˲Ù×÷ϵͳµÄÄں˾µ ÏñÀ´¼ÓÈëÐµĹ¦ÄÜ¡£Õ⻹Òâζ×ÅÒ»¸öÓ·Ö×µÄÄںˡ£
ÄÚºËÄ£¿éÊÇÈçºÎ±»µ÷ÈëÄں˹¤×÷µÄ£¿
Äã¿ÉÒÔͨ¹ýÖ´ÐÐlsmodÃüÁîÀ´²é¿´ÄÚºËÒѾ¼ÓÔØÁËÄÄ Ð©ÄÚºËÄ£¿é, ¸ÃÃüÁîͨ¹ý¶ÁÈ¡/proc/modulesÎļþµÄÄÚÈÝ À´»ñµÃËùÐèÐÅÏ¢¡£
ÕâЩÄÚºËÄ£¿éÊÇÈçºÎ±»µ÷ÈëÄں˵ģ¿µ±²Ù×÷ϵͳÄÚºËÐèÒªµÄÀ©Õ¹¹¦Äܲ»´æ ÔÚʱ£¬ÄÚºËÄ£¿é¹ÜÀíÊØ»¤½ø³Ìkmod[1]Ö´ÐÐmodprobeÈ¥¼ÓÔØÄÚºËÄ£ ¿é¡£Á½ÖÖÀàÐ͵IJÎÊý±»´«µÝ¸ømodprobe£º
Ò»¸öÄÚºËÄ£¿éµÄÃû×ÖÏñsoftdog»òÊÇppp¡£
ͨÓÃʶ±ð·ûÏñchar-major-10-30¡£
µ±´«µÝ¸ømodprobeÊÇͨÓÃʶ±ð·ûʱ£¬modprobeÊ×ÏÈÔÚÎļþ /etc/modules.conf²éÕÒ¸Ã×Ö·û´®¡£Èç¹ûËü·¢ÏÖµÄÒ»ÐбðÃûÏñ£º
alias char-major-10-30 softdog
Ëü¾ÍÃ÷°×ͨÓÃʶ±ð·ûÊÇÖ¸ÏòÄÚºËÄ£¿ésoftdog.o¡£
È»ºó£¬modprobe±éÀúÎļþ/lib/modules/version/modules.dep À´ÅжÏÊÇ·ñÓÐÆäËüÄÚºËÄ£¿éÐèÒªÔÚ¸ÃÄ£¿é¼ÓÔØÇ°±»¼ÓÔØ¡£¸ÃÎļþÊÇÓÉÃüÁîdepmod -a ½¨Á¢£¬±£´æ×ÅÄÚºËÄ£¿éµÄÒÀÀµ¹Øϵ¡£¾ÙÀýÀ´Ëµ£¬msdos.oÒÀÀµÓÚÄ£¿éfat.o ÄÚºËÄ£¿éÒѾ±»ÄÚºËÔØÈë¡£µ±Òª¼ÓÔصÄÄÚºËÄ£¿éÐèҪʹÓñðµÄÄ£¿éÌṩµÄ·ûºÅÁ´½Óʱ£¨¶à°ëÊDZäÁ¿»òº¯Êý£©£¬ ÄÇôÄÇЩÌṩÕâЩËùÐè·ûºÅÁ´½ÓµÄÄÚºËÄ£¿é¾Í±»¸ÃÄ£¿éËùÒÀÀµ¡£
×îÖÕ£¬modprobeµ÷ÓÃinsmodÏȼÓÔر»ÒÀÀµµÄÄ£¿é£¬È»ºó¼ÓÔظñ»ÄÚºËÒªÇóµÄÄ£¿é¡£modprobe½«insmodÖ¸Ïò /lib/modules/version/[2]Ŀ¼£¬¸ÃĿ¼ΪĬÈϱê×¼´æ·ÅÄÚºËÄ£¿éµÄĿ¼¡£insmod¶ÔÄÚºËÄ£¿é´æ·ÅλÖà µÄ´¦ÀíÏ൱´ô°å£¬ËùÒÔmodprobeÓ¦¸ÃºÜÇå³þµÄÖªµÀĬÈϱê×¼µÄÄÚºËÄ£¿é´æ·ÅµÄλÖá£ËùÒÔ£¬µ±ÄãÏëÒªÔØÈëÒ»¸öÄÚ ºËÄ£¿éʱ£¬Äã¿ÉÒÔÖ´ÐУº
insmod /lib/modules/2.5.1/kernel/fs/fat/fat.o
insmod /lib/modules/2.5.1/kernel/fs/msdos/msdos.o
»òÖ»ÊÇÖ´ÐÐ"modprobe -a msdos"¡£
LinuxÌṩmodprobe, insmod and depmodÔÚÒ»¸öÃûΪmodutils »ò mod-utilsµÄ¹¤¾ß°üÄÚ¡£
ÔÚ½áÊø±¾ÕÂÇ°£¬ÈÃÎÒÃÇÀ´¿´Ò»¸ö /etc/modules.confÎļþ£º
#This file is automatically generated by update-modules
path[misc]=/lib/modules/2.4.?/local
keep
path[net]=~p/mymodules
options mydriver irq=10
alias eth0 eepro
ÓÃ'#'ÆðʼµÄÐÐΪעÊÍ¡£¿Õ°×Ðб»ºöÂÔ¡£
ÒÔ path[misc]ÆðʼµÄÐиæËßmodprobeÓà /lib/modules/2.4.?/localÌæ´úËÑÑ° miscÄÚºËÄ£¿éµÄ·¾¶¡£ÕýÈçÄã¿´µ½µÄ£¬ÃüÁî½âÊÍÆ÷shellµÄÔª×Ö·ûÒ²¿ÉÒÔʹÓá£
ÒÔpath[net]ÆðʼµÄÐиæËßmodprobe ÔÚĿ¼ ~p/mymodulesËÑË÷ÍøÂç·½ÃæµÄÄÚºËÄ£¿é¡£µ«ÊÇ£¬ÔÚpath[net] Ö¸Áî֮ǰʹÓõÄ"keep" Ö¸Áî¸æËßmodprobeÖ»Êǽ«¸Ã·¾¶Ìí¼Óµ½±ê×¼ËÑË÷·¾¶ÖУ¬¶ø²»ÊÇÏñ¶Ô´ý miscÇ°ÃæÄÇÑù½øÐÐÌæ»»¡£
ÒÔalias ÆðʼµÄµÄÐÐʹmodprobe¼ÓÔØeepro.oµ±kmod ÒÔͨÓÃʶ±ð·û'eth0' ÒªÇó¼ÓÔØÏàÓ¦ÄÚºËÄ£¿éʱ¡£
Äã²»»á·¢ÏÖÏñ"alias block-major-2 floppy"ÕâÑùµÄ±ðÃûÐÐÔÚÎļþ/etc/modules.conf ÒòΪmodprobeÒѾ֪µÀÔÚ¾ø´ó¶àÊýϵͳÉÏ°²×°µÄ±ê×¼µÄÉ豸µÄÇý¶¯Ä£¿é¡£
ÏÖÔÚÄãÒѾ֪µÀÄÚºËÄ£¿éÊÇÈçºÎ±»µ÷ÈëµÄÁË¡£µ±ÄãÏëдÄã×Ô¼ºµÄÒÀÀµÓÚÆäËüÄ£¿éµÄÄÚºËÄ£¿éʱ£¬ »¹ÓÐһЩÄÚÈÝûÓÐÌṩ¡£Õâ¸öÏà¶Ô¸ß¼¶µÄÎÊÌ⽫ÔÚÒÔºóµÄÕ½ÚÖнéÉÜ£¬µ±ÎÒÃÇÒѾÍê³ÉÇ°ÃæµÄѧϰºó¡£
ÔÚ¿ªÊ¼Ç°
ÔÚÎÒÃǽéÉÜÔ´´úÂëÇ°£¬ÓÐһЩÊÂÐèҪעÒ⡣ϵͳ±Ë´ËÖ®¼äµÄ²»Í¬»áµ¼ÖÂÐí¶àÀ§ÄÑ¡£ ˳ÀûµÄ±àÒë²¢ÇÒ¼ÓÔØÄãµÄµÚÒ»¸ö"hello world"Ä£¿éÓÐʱ¾Í»á±È½ÏÀ§ÄÑ¡£µ«Êǵ±Äã¿ç¹ý ÕâµÀ¿²Ê±£¬ºóÃæ»á˳ÀûµÄ¶à¡£
ÄÚºËÄ£¿éºÍÄں˵İ汾ÎÊÌâ
Ϊij¸ö°æ±¾±àÒëµÄÄ£¿é½«²»Äܱ»ÁíÒ»¸ö°æ±¾µÄÄں˼ÓÔØÈç¹ûÄÚºËÖдò¿ªÁË CONFIG_MODVERSIONSÑ¡Ïî¡£ÎÒÃÇÔÝʱ²»»áÌÖÂÛÓë´ËÏà¹ØµÄ ÄÚÈÝ¡£ÔÚÎÒÃǽøÈëÏà¹ØÄÚÈÝÇ°£¬±¾ÎĵµÖеķ¶Àý¿ÉÄÜÔÚ¸ÃÑ¡Ïî´ò¿ªµÄÇé¿öÏÂÎÞ·¨ ¹¤×÷¡£µ«ÊÇ£¬Ä¿Ç°¾ø´ó¶àÊýµÄ·¢ÐаæÊǽ«¸ÃÑ¡Ïî´ò¿ªµÄ¡£ËùÒÔÈç¹ûÄãÓöµ½ºÍ°æ±¾ Ïà¹ØµÄ´íÎóʱ£¬×îºÃ£¬ÖØбàÒëÒ»¸ö¹Ø±Õ¸ÃÑ¡ÏîµÄÄںˡ£
ʹÓà X´øÀ´µÄÎÊÌâ
Ç¿ÁÒ½¨ÒéÄãÔÚ¿ØÖÆ̨ÏÂÊäÈëÎĵµÖеķ¶Àý´úÂ룬±àÒëÈ»ºó¼ÓÔØÄ£¿é£¬¶ø²»ÊÇÔÚXÏ¡£
Ä£¿é²»ÄÜÏñprintf()ÄÇÑùÊä³öµ½ÆÁÄ»£¬µ«ËüÃÇ¿ÉÒÔ ¼Ç¼ÐÅÏ¢ºÍ¾¯¸æ£¬µ±ÇÒ½öµ±ÄãÔÚʹÓÿØÖÆ̨ʱÕâЩÐÅÏ¢²ÅÄÜ×îÖÕÏÔʾÔÚÆÁÄ»ÉÏ¡£ Èç¹ûÄã´ÓxtermÖÐinsmodÒ»¸öÄ£¿é£¬ÕâЩÈÕÖ¾ÐÅÏ¢Ö»»á¼Ç¼ÔÚÄãµÄÈÕÖ¾ÎļþÖС£ ³ýÁ˲鿴ÈÕÖ¾ÎļþÄ㽫ÎÞ·¨ µÃµ½Êä³öÐÅÏ¢¡£ÏëÒª¼°Ê±µÄ»ñµÃÕâЩÈÕÖ¾ÐÅÏ¢£¬½¨Òé ËùÓеŤ×÷¶¼ÔÚ¿ØÖÆ̨ϽøÐС£
±àÒëÏà¹ØºÍÄں˰汾Ïà¹ØµÄÎÊÌâ
LinuxµÄ·¢Ðа澳£¸øÄں˴òһЩ·Ç±ê×¼µÄ²¹¶¡£¬ÕâÖÖÇé¿ö»Øµ¼ÖÂһЩÎÊÌâµÄ·¢Éú¡£
Ò»¸ö¸üÆÕ±éµÄÎÊÌâÊÇһЩLinux·¢ÐаæÌṩµÄÍ·Îļþ²»ÍêÕû¡£±àÒëÄ£¿éʱÄ㽫ÐèÒª·Ç³£¶à µÄÄÚºËÍ·Îļþ¡£Ä«·Æ·¨ÔòÖ®Ò»¾ÍÊÇÄÇЩȱÉÙµÄÍ·ÎļþÇ¡Ç¡ÊÇÄã×îÐèÒªµÄ¡£
ÎÒÇ¿ÁÒ½¨Òé´ÓLinux¾µÏñÕ¾µãÏÂÔØÔ´´úÂë°ü£¬±àÒëÐÂÄں˲¢ÓÃÐÂÄÚºËÆô¶¯ÏµÍ³À´±ÜÃâÒÔÉÏ µÄÎÊÌâ¡£²ÎÔÄ"Linux Kernel HOWTO"»ñµÃÏêϸÄÚÈÝ¡£
¾ßÓзí´ÌÒâζµÄÊÇ£¬ÕâÒ²»áµ¼ÖÂһЩÎÊÌâ¡£gccÇãÏòÓÚÔÚȱʡµÄÄÚºËÔ´Îļþ·¾¶(ͨ³£ÊÇ/usr/src/)ÏÂÑ°ÕÒÔ´´úÂëÎļþ¡£Õâ¿ÉÒÔͨ¹ýgccµÄ-I Ñ¡ÏîÀ´Çл»¡£
Notes
[1] ÔÚÔçÆÚµÄlinux°æ±¾ÖУ¬ÊÇ Ò»¸öÃûΪkerneldµÄÊØ»¤½ø³Ì¡£
[2] Èç¹ûÄãÔÚÐÞ¸ÄÄںˣ¬Îª±ÜÃâ ¸²¸ÇÄãÏÖÔÚ¹¤×÷µÄÄ£¿é£¬ÄãÓ¦¸ÃÊÔÊÔʹÓÃÄÚºËMakefileÖеıäÁ¿EXTRAVERSIONÈ¥½¨Á¢Ò»¸ö¶À Á¢µÄÄ£¿éĿ¼¡£
pengdejiu ÓÚ 2009-12-27 00:21:41·¢±í:
Å££¬¿´²»¶®£¬¶¥Ò»¸ö
masterlinux ÓÚ 2009-11-06 11:26:28·¢±í:
masterlinux ÓÚ 2009-11-06 11:25:56·¢±í:
¶¥
cxqcxq0177 ÓÚ 2006-12-12 10:24:54·¢±í:
:0D1 £¬ÏÂÏÂÀ´¿´¿´
febspeolal ÓÚ 2006-11-09 01:13:20·¢±í:
Chapter 14. Common Pitfalls
×¢Òâ
ÔÚÎÒÈÃÄãÃǽøÈëÄÚºËÄ£¿éµÄÊÀ½ç֮ǰ£¬ÎÒÐèÒªÌáÐÑÄãÃÇÏÂÃæµÄһЩעÒâ¡£Èç¹ûÎÒû¾¯¸æµ½ÄãÃǵ«ÊǵÄÈ··¢ÉúÁË£¬ ÄÇôÄ㽫ÎÊÌⱨ¸æÎÒ£¬ÎÒ½«È«¶îÍË»¹ÄãµÄÊé¿î¡£
ʹÓñê×¼¿âÎļþ:
ÄãÎÞ·¨ÕâÑù×ö¡£ÔÚÄÚºËÄ£¿éÖУ¬ÄãÖ»ÄÜʹÓÃÄÚºËÌṩµÄº¯Êý£¬Ò²¾ÍÊÇÄãÔÚ /proc/kallsymsÄܲ鵽µÄÄÇЩ¡£
½ûÓÃÖжÏ:
ÄãÈç¹ûÕâÑù×öÁ˵«Ö»ÊÇһ˲¼ä£¬Ã»ÎÊÌ⣬µ±ÎÒûÌáÕâÊ¡£µ«ÊÇʺóÄãûÓлָ´ËüÃÇ£¬ Äã¾ÍÖ»ÄÜÞôµçÔ´¼üÀ´ÖØÆôÄ㽩ËÀµÄϵͳÁË¡£
³¢ÊÔһЩ·Ç³£Î£ÏյĶ«Î÷:
ÕâÒ²Ðí²»Ó¦¸ÃÓÉÎÒÀ´Ëµ£¬µ«ÊÇÒÔ·ÀÍòÒ»£¬ÎÒ»¹ÊÇÌá³öÀ´°É£¡
Appendix A. Changes: 2.0 To 2.2
´Ó2.0µ½2.2µÄ±ä»¯
´Ó2.0µ½2.2µÄ±ä»¯
ÎÒ¶ÔÄں˵ÄÁ˽Ⲣ²»ºÜÍêÈ«ËùÒÔÎÒÒ²ÎÞ·¨Ð´³öËùÓеı仯¡£ÔÚÐ޸ĴúÂë £¨¸üÈ·ÇеÄ˵£¬ÊDzÉÓÃEmmanuel PapirakisµÄÐ޸ģ©Ê±£¬ÎÒÓöµ½ÁËÒÔϵÄÕâЩÐ޸ġ£ ÎÒ½«ËüÃǶ¼ÁгöÀ´ÒÔ·½±ãÄ£¿é±àдÕßÃÇ£¬ÌرðÊÇѧϰ¸Ãµµ°¸ÏÈÇ°°æ±¾²¢ÊìϤÎÒÌáµ½µÄÕâЩ¼¼ÇÉ £¨µ«ÒѾ¸ü»»µ½Ð°汾µÄ£©µÄÄÇЩÈË¡£
¸ü¶àµÄÕâ·½ÃæµÄ²Î¿¼×ÊÁÏÔÚ Richard Gooch'sµÄÕ¾µãÉÏ¡£
asm/uaccess.h
Èç¹ûÄãҪʹÓÃput_user»òget_userÄã¾ÍÐèÒª #includeËü¡£
get_user
ÔÚ2.2°æ±¾ÖУ¬get_userͬʱ½ÓÊÕÓû§ÄÚ´æµÄÖ¸ÕëºÍÓÃÀ´ ÉèÖÃÐÅÏ¢µÄÄÚºËÄÚ´æÖбäÁ¿µÄÄÚ´æÖ¸Õë¡£±ä»¯µÄÔÒòÊÇÒòΪµ±ÎÒÃǶÁÈ¡µÄ±äÁ¿ÊǶþ»òËĸö×Ö½Ú³¤µÄʱºò£¬ get_userÒ²¿ÉÒÔ¶ÁÈ¡¶þ»òËĸö×Ö½Ú³¤µÄ±äÁ¿¡£
file_operations
¸Ä½á¹¹ÌåÏÖÔÚÓÐÁËÒ»¸ö¿ÉÒÔÔÚopenºÍ closeÖ®¼ä½øÐеÄˢвÙ×÷º¯Êý¡£
close in file_operations
2.2°æ±¾ÖУ¬close·µ»ØÕûÐÎÖµ£¬ËùÒÔ¿ÉÒÔ¼ì²âÊÇ·ñʧ°Ü¡£
read,write in file_operations
ÕâЩº¯ÊýµÄÍ·Îļþ¸Ä±äÁË¡£ËüÃÇÏÖÔÚ·µ»Øssize_t¶ø²»ÊÇÕûÐÎÖµ£¬ ÇÒËüÃǵIJÎÊý±íÒ²±äÁË¡£inode ²»ÔÙÊÇÒ»¸ö²ÎÊý£¬ÎļþÖеÄÆ«ÒÆÁ¿Ò²Ò»Ñù¡£
proc_register_dynamic
¸Ãº¯ÊýÒѾ²»¸´´æÔÚ¡£ÄãÓ¦¸ÃʹÓÃÓÃ0×÷Ϊinode²ÎÊýµÄproc_register º¯ÊýÀ´Ìæ´úËü¡£
Signals
ÔÚ task ½á¹¹ÌåÖеÄsignals²»ÔÙÊÇÒ»¸ö32λÕûÐαäÁ¿£¬¶øÊÇÒ»¸öΪ _NSIG_WORDS ÕûÐεÄÊý×é¡£
queue_task_irq
¼´Ê¹ÄãÏëÔÚÖжϴ¦ÀíÄÚ²¿µ÷¶ÈÒ»¸öÈÎÎñ£¬ÄãÒ²Ó¦¸ÃʹÓà queue_task¶ø²»ÊÇqueue_task_irq¡£
Module Parameters
Äã²»±ØÔÚ½«Ä£¿é²ÎÊýÉùÃ÷Ϊȫ¾Ö±äÁ¿¡£ÔÚ2.2ÖУ¬Ê¹Óà MODULE_PARMÈ¥ÉùÃ÷Ä£¿é²ÎÊý¡£ÕâÊÇÒ»¸ö½ø²½£¬ ÕâÑù¾ÍÔÊÐíÄ£¿é½ÓÊÜÒÔÊý×Ö¿ªÍ·µÄ²ÎÊýÃû¶ø²»»á±»ÅªºýÍ¿¡£
Symmetrical Multi-Processing
Äں˱¾Ê¡ÒѲ»ÔÙÊÇÒ»¸öspinlock£¬Òâζ×ÅÄãµÄÄ£¿éÒ²Ó¦¸Ã¿¼ÂÇ SMPµÄÎÊÌâ¡£
Appendix B. Where To Go From Here
ΪʲôÕâÑùд£¿
ÎÒÆäʵ¿ÉÒÔ¸øÕâ±¾ÊéÔÙ¼ÓÈ뼸Õ£¬ÀýÈçÈçºÎΪʵÏÖеÄÎļþϵͳ¼ÓÉÏÒ»Õ£¬»òÊÇÌí¼ÓÒ»¸öеÄÐÒéÕ»£¨Èç¹ûÓÐÕâÑùµÄ±ØÒªµÄ»°£¬ ÏëÕÒµ½Linux²»Ö§³ÖµÄÍøÂçÐÒéÒѾÊǷdz£µÄÀ§ÄѵÄÁË£©¡£ÎÒ»¹¿ÉÒÔ½âÊÍÒ»ÏÂÎÒÃÇÉÐδ½Ó´¥µ½µÄÄÚºËʵÏÖ»úÖÆ£¬ÏñϵͳµÄÒýµ¼×Ô¾Ù£¬ »ò´ÅÅÌ´æ´¢¡£
µ«ÊÇ£¬ÎÒ¾ö¶¨·ñ¡£ÎÒд±¾ÊéµÄÄ¿µÄÊÇÌṩ»ù±¾µÄ£¬ÈëÃŵĶÔÉñÃصÄÄÚºËÄ£¿é±à³ÌµÄÈÏʶºÍÕâ·½ÃæµÄ³£Óü¼ÇÉ¡£ ¶ÔÓÚÄÇЩ·Ç³£ÈÈÖÔÓëÄں˱à³ÌµÄÈË£¬ÎÒÍƼöJuan-Mariano de GoyenecheµÄ ÄÚºË×ÊÔ´ÁÐ±í ¡£ ͬÑù£¬¾ÍͬLinus±¾ÈË˵µÄÄÇÑù£¬Ñ§Ï°ÄÚºË×îºÃµÄ·½·¨ÊÇ×Ô¼ºÔĶÁÄÚºËÔ´´úÂë¡£
Èç¹ûÄã¶Ô¸ü¶àµÄ¶ÌСµÄʾÀýÄÚºËÄ£¿é¸ÐÐËȤ£¬ÎÒÏòÄãÍƼö Phrack magazine Õâ±¾ÔÓÖ¾¡£ ¼´Ê¹Äã²»¹ØÐÄ°²È«ÎÊÌ⣬×÷Ϊһ¸ö³ÌÐòÔ±Ä㻹ÊÇÓ¦¸Ãʱʱ¿¼ÂÇÕâ¸öÎÊÌâµÄ¡£ÕâЩÄÚºËÄ£¿é´úÂ붼ºÜ¶Ì£¬²»ÐèÒª·Ñ¶à´ó¾¢¾ÍÄܶÁ¶®¡£
ÎÒÏ£ÍûÎÒÂú×ãÁËÄãÏ£Íû³ÉΪһ¸ö¸üÓÅÐãµÄ³ÌÐòÔ±µÄÒªÇó£¬ÖÁÉÙÔÚѧϰ¼¼ÊõµÄ¹ý³ÌÖÐÌå»áµ½ÁËÀÖȤ¡£ Èç¹ûÄãÕæµÄдÁËһЩ·Ç³£ÓÐÓõÄÄ£¿é£¬ÎÒÏ£ÍûÄãʹÓÃGPLÐí¿ÉÖ¤·¢²¼ÄãµÄÄ£¿é£¬ÕâÑùÎÒÒ²¾Í¿ÉÒÔʹÓÃËüÃÇÁË¡£
febspeolal ÓÚ 2006-11-09 01:12:49·¢±í:
Chapter 13. Symmetric Multi Processing
¶Ô³Æ¶àÏ̴߳¦Àí
Ìá¸ßÐÔÄܵÄ×î¼òµ¥Ò²ÊÇ×î±ãÒ˵ķ½·¨ÊǸøÄãµÄÖ÷°å¼ÓµÚ¶þ¸öCPU£¨Èç¹ûÄãµÄÖ÷°åÖ§³ÖµÄ»°£©¡£ Õâ¿ÉÒÔͨ¹ýÈò»Í¬µÄCPUÍê³É²»Í¬µÄ¹¤×÷£¨·Ç¶Ô³Æ¶àÏ̴߳¦Àí£©»òÊÇÏàͬµÄ¹¤×÷£¨¶Ô³Æ¶àÏ̴߳¦Àí£©¡£ ʵÏÖ¸ßЧÂʵķǶԳƵĶàÏ̴߳¦ÀíÐèÒªÌØÊâÓ²¼þÏà¹ØµÄ֪ʶ£¬¶ø¶ÔÓÚLinuxÕâÑùͨÓòÙ×÷ϵͳÕâÊDz»¿ÉÄܵġ£ Ïà¶Ô¶øÑÔ£¬¶Ô³Æ¶àÏ̴߳¦ÀíÊǽÏÈÝÒ×ʵÏֵġ£
ÎÒÕâÀïËù˵µÄÏà¶ÔÈÝÒ×£¬ÀÏʵ˵£¬»¹ÊDz»ÈÝÒס£ÔÚÒ»¸ö¶Ô³Æ¶àÏ̴߳¦ÀíµÄ»·¾³ÖУ¬ ¶à¸öCPU¹²ÏíÄڴ棬µ¼ÖµĽá¹ûÊÇÆäÖÐÒ»¸öCPUÔËÐеĴúÂë»á¶Ô±ðµÄCPUÒ²²úÉúÓ°Ïì¡£ Äã²»ÄÜÔÙÈ·¶¨Äã´úÂëÖеÚÒ»ÐÐÖÐÉèÖõıäÁ¿ÔÚ½ÓÏÂÀ´µÄÄÇÐдúÂëÖл¹ÊÇÄǸöÉèÖÃÖµ£» ÆäËüµÄCPU¿ÉÄÜ»á³ÃÄã²»×¢ÒâÒѾ°ÑËüÐÞ¸ÄÁË¡£ÏÔÈ»£¬Èç¹ûÊÇÕâÑùµÄ»°£¬ÊÇÎÞ·¨½øÐÐÈκαà³ÌµÄ¡£
¶ÔÓÚ½ø³Ì²ãÃæÉϵıà³ÌÕâͨ³£²»ÊǸöÎÊÌ⣬ÒòΪһ¸ö½ø³Ìͨ³£Í¬Ò»Ê±¼äÖ»ÔÚÒ»¸öCPUÉÏÔËÐÐ [1]¡£ µ«ÊÇ£¬¶ÔÓÚÄںˣ¬¾Í¿ÉÒÔ±»ÔÚ²»Í¬µÄCPUÉϵÄͬʱÔËÐеIJ»Í¬µÄ½ø³ÌʹÓá£
ÔÚÄں˰汾2.0.xÖУ¬Õ⻹²»Ëã×÷ʲôÎÊÌ⣬ÒòΪÕû¸öÄÚºËÊÇÒ»¸öspinlock [2]£¬Õâ¾ÍÒâζ×ÅÒ»µ©Ä³¸öCPU½øÈëÄÚºË̬£¬±ðµÄCPU½«²»ÔÊÐí½øÈëÄÚºË̬¡£ÕâʹLinuxµÄSMPʵÏֺܰ²È« [3]£¬µ«È±·¦Ð§ÂÊ¡£
ÔÚÄں˰汾2.2.xÒԺ󣬶àCPUÒѾÔÊÐíͬʱ½øÈëÄÚºË̬¡£ÄÚºËÄ£¿éµÄ×÷ÕßÓ¦¸ÃÒâʶµ½ÕâÒ»µã¡£
Notes
[1] ´æÔÚÀýÍ⣬¾ÍÊÇÏ̻߳¯µÄ½ø³Ì£¬ÕâÑùµÄ½ø³Ì¿ÉÒÔÔÚ¶à¸öCPUÉÏͬʱÔËÐС£
[2] ±§Ç¸£¬ÎÒûÓÐÕÒµ½ºÏÊʵĴÊÓïÀ´±í´ïÕâ¸öµ¥´Ê¡£ÕâÊÇÄÚºËÖеÄÒ»ÖÖ»úÖÆ£¬¿ÉÒÔ¶ÔÄÚºËÖеĹؼüÊý¾Ý½á¹¹½øÐÐËø¶¨±£»¤£¬ ·ÀÖ¹Æä±»ÆÆ»µ¡£
[3] Òâζ×ÅÕâÑùµÄSMP»úÖÆʹÓÃÆðÀ´ºÜ°²È«¡£
febspeolal ÓÚ 2006-11-09 01:12:31·¢±í:
Chapter 12. Interrupt Handlers
/* We're doing kernel work */
/* Specifically, a module */
/* We want an interrupt */
Interrupt Handlers
Interrupt Handlers
³ýÁ˸սáÊøµÄÄÇÕ£¬ÎÒÃÇÄ¿Ç°ÔÚÄÚºËÖÐËù×öµÄÿ¼þʶ¼Ö»²»¹ýÊǶÔij¸öÇëÇóµÄ½ø³ÌµÄÏìÓ¦£¬ ҪôÊǶÔij¸öÌØÊâµÄÎļþµÄ´¦Àí£¬ÒªÃ´ÊÇ·¢ËÍÒ»¸öioctl()£¬ÒªÃ´Êǵ÷ÓÃÒ»¸öϵͳµ÷Óᣠµ«ÊÇÄں˵Ť×÷²»½ö½öÊÇÏìӦij¸ö½ø³ÌµÄÇëÇó¡£»¹ÓÐÁíÍâÒ»Ïî·Ç³£ÖØÒªµÄ¹¤×÷¾ÍÊǸºÔð¶ÔÓ²¼þµÄ¹ÜÀí¡£
ÔÚCPUºÍÓ²¼þÖ®¼äµÄ»î¶¯´óÖ¿ɷÖΪÁ½ÖÖ¡£µÚÒ»ÖÖÊÇCPU·¢ËÍÖ¸Áî¸øÓ²¼þ£¬µÚ¶þÖÖ¾ÍÊÇÓ²¼þÒª·µ»ØijЩÐÅÏ¢¸øCPU¡£ ºóÃæµÄÄÇÖÖÓÖ½Ð×öÖжϣ¬ÒòΪҪ֪µÀºÎʱͬӲ¼þ¶Ô»°²ÅÊÊÒ˶ø½ÏÄÑʵÏÖ¡£Ó²¼þÉ豸ͨ³£Ö»ÓкÜÉٵĻº´æ£¬ Èç¹ûÄã²»¼°Ê±µÄ¶ÁÈ¡ÀïÃæµÄÐÅÏ¢£¬ÕâЩÐÅÏ¢¾Í»á¶ªÊ§¡£
ÔÚLinuxÖУ¬Ó²¼þÖжϱ»½Ð×÷IRQ£¨Interrupt Requests£¬ÖжÏÇëÇó£©[1]¡£ÓÐÁ½ÖÖÓ²¼þÖжϣ¬¶ÌÖжϺͳ¤Öжϡ£¶ÌÖжÏÕ¼ÓõÄʱ¼ä·Ç³£¶Ì£¬ÔÚÕâ¶Îʱ¼äÄÚ£¬ Õû¸öϵͳ±»×èÈû£¬ÈκÎÆäËüÖж϶¼²»»á´¦Àí¡£³¤ÖжÏÕ¼ÓõÄʱ¼äÏà¶Ô½Ï³¤£¬ÔÚ´ËÆڼ䣬¿ÉÄÜ»áÓбðµÄÖжϷ¢ÉúÇëÇó´¦Àí £¨²»ÊÇÏàͬÉ豸·¢³öµÄÖжϣ©¡£¿ÉÄܵĻ°£¬¾¡Á¿½«ÖжÏÉùÃ÷Ϊ³¤Öжϡ£
µ±CPU½ÓÊÕµ½Ò»¸öÖжÏʱ£¬ËüÍ£Ö¹ÕýÔÚ´¦ÀíµÄÒ»ÇÐÊÂÎñ£¨³ý·ÇËüÔÚ´¦ÀíÁíÒ»¸ö¸üÖØÒªµÄÖжϣ¬ ÔÚÕâÖÖÇé¿öÏÂËüÖ»»á´¦ÀíÍêÕâ¸öÖØÒªµÄÖжϲŻá»ØÀ´´¦ÀíвúÉúµÄÖжϣ©£¬ ½«ÔËÐÐÖеÄÄÇЩ²ÎÊýѹÈëÕ»ÖÐÈ»ºóµ÷ÓÃÖжϴ¦Àí³ÌÐò¡£ÕâͬʱÒâζ×ÅÖжϴ¦Àí³ÌÐò±¾ÉíÒ²ÓÐһЩÏÞÖÆ£¬ ÒòΪ´ËʱϵͳµÄ״̬²¢²»È·¶¨¡£½â¾öµÄ°ì·¨ÊÇÈÃÖжϴ¦Àí³ÌÐò¾¡¿ìµÄÍê³ÉËüµÄÊÂÎñ£¬Í¨³£ÊÇ´ÓÓ²¼þ¶ÁÈ¡ÐÅÏ¢ºÍÏòÓ²¼þ·¢ËÍÖ¸Á È»ºó°²ÅÅÏÂÒ»´Î½ÓÊÕÐÅÏ¢µÄÏà¹Ø´¦Àí£¨Õâ±»³ÆΪ"bottom half" [2] )£¬È»ºó·µ»Ø¡£ÄÚºËÈ·±£±»°²ÅŵÄÊÂÎñ±»¾¡¿ìµÄÖ´ÐС£µ±±»Ö´ÐÐʱ£¬ÔÚÄÚºËÄ£¿éÖÐÔÊÐíµÄ²Ù×÷¾ÍÊDZ»ÔÊÐíµÄ¡£
ʵÏֵķ½·¨Êǵ÷ÓÃrequest_irq()º¯Êý£¬µ±½ÓÊܵ½ÏàÓ¦µÄIRQʱ £¨¹²ÓÐ15ÖÖÖжϣ¬ÔÚIntel¼Ü¹¹Æ½Ì¨ÉÏÔÙ¼ÓÉÏ1ÖÖÓÃÓÚ´®Á¬ÖжϿØÖÆÆ÷µÄÖжϣ©È¥µ÷ÓÃÄãµÄÖÐ¶Ï ´¦Àí³ÌÐò¡£¸Ãº¯Êý½ÓÊÕIRQºÅ£¬Òªµ÷ÓõĴ¦ÀíIRQº¯ÊýµÄÃû³Æ£¬ÖжÏÇëÇóµÄÀà±ð±ê־룬Îļþ /proc/interruptsÖÐÉùÃ÷µÄÉ豸µÄÃû×Ö£¬ºÍ´«µÝ¸øÖжϴ¦Àí³ÌÐòµÄ²ÎÊý¡£ÖжÏÇëÇóµÄÀà±ð±ê־λ¿ÉÒÔΪ SA_SHIRQÀ´¸æËßϵͳÄãÏ£ÍûÓëÆäËüÖжϴ¦Àí³ÌÐò¹²Ïí¸ÃÖжϺŠ£¨Õâͨ³£ÊÇÓÉÓÚһЩÉ豸¹²ÓÃÏàͬµÄIRQºÅ£©£¬Ò²¿ÉÒÔΪSA_INTERRUPT À´¸æËßϵͳÕâÊÇÒ»¸ö¿ìËÙÖжϣ¬ÕâÖÖÇé¿öϸú¯ÊýÖ»ÓÐÔÚ¸ÃIRQ¿ÕÏÐʱ²Å»á³É¹¦·µ»Ø£¬»òÕßͬʱÄãÓÖ¾ö¶¨¹²Ïí¸ÃIQR¡£
È»ºó£¬ÔÚÖжϴ¦Àí³ÌÐòÄÚ²¿£¬ÎÒÃÇÓëÓ²¼þ¶Ô»°£¬½Ó×ÅʹÓôøtq_immediate()ºÍ mark_bh(BH_IMMEDIATE)µÄ queue_task_irq()È¥¶Ôbottom half¶ÓÁнøÐе÷¶È¡£ÎÒÃDz»ÄÜʹÓÃ2.0°æ±¾ÖÖ±ê×¼µÄ queue_task µÄÔÒòÊÇÖжϿÉÄܾͷ¢ÉúÔÚ±ðÈ赀 queue_task[3] ÖС£ÎÒÃÇÐèÒªmark_bhÊÇÒòΪÔçÆÚ°æ±¾µÄLinuxÖ»ÓÐÒ»¸ö¿ÉÒÔ´æ´¢32¸öbottom halfµÄÊý×飬 ²¢ÇÒÏÖÔÚËüÃÇÖеÄÒ»¸ö(BH_IMMEDIATE)ÒѾ±»ÓÃÀ´Á¬½ÓûÓзÖÅäµ½¶ÓÁÐÖеÄÈë¿ÚµÄÓ²¼þ Çý¶¯µÄbottom half¡£
Intel¼Ü¹¹ÖеļüÅÌ
Ê£ÓàµÄÕⲿ·ÖÊÇÖ»ÊÊÓÃIntel¼Ü¹¹µÄ¡£Èç¹ûÄ㲻ʹÓÃIntel¼Ü¹¹µÄƽ̨£¬ËüÃǽ«²»»á¹¤×÷£¬²»ÒªÈ¥³¢ÊÔ±àÒëÒÔϵĴúÂë¡£
ÔÚдÕâÕµÄÊÂÀý´úÂëʱ£¬ÎÒÓöµ½ÁËһЩÀ§ÄÑ¡£Ò»·½Ã棬ÎÒÐèÒªÒ»¸ö¿ÉÒԵõ½Êµ¼ÊÓÐÒâÒå½á¹ûµÄ£¬ ÄÜÔÚ¸÷ÖÖƽ̨ÉϹ¤×÷µÄÀý×Ó¡£ÁíÒ»·½Ã棬ÄÚºËÖÐÒѾ°üÀ¨Á˸÷ÖÖÉ豸Çý¶¯£¬²¢ÇÒÕâЩÇý¶¯½«ÎÞ·¨ºÍÎÒµÄÀý×Ó¹²´æ¡£ ÎÒÕÒµ½µÄ½â¾ö°ì·¨ÊÇΪ¼üÅÌÖжÏдµã¶«Î÷£¬µ±È»Ê×ÏȽûÓÃÆÕͨµÄ¼üÅÌÖжϡ£ÒòΪ¸ÃÖжÏÔÚÄÚºËÖж¨ÒåΪһ¸ö¾²Ì¬Á¬½ÓµÄ·ûºÅ £¨¼ûdrivers/char/keyboard.c)£©£¬ÎÒÃÇûÓа취»Ö¸´¡£ËùÒÔÔÚ insmodÇ°£¬Èç¹ûÄ㰮ϧÄãµÄ»úÆ÷£¬Ð´ò¿ªÒ»¸öÖÕ¶ËÔËÐÐsleep 120 ; reboot¡£
¸Ã´úÂ뽫×Ô¼º°ó¶¨ÔÚIRQ 1£¬ Ò²¾ÍÊÇIntel¼Ü¹¹ÖмüÅ̵ÄIRQ¡£È»ºó£¬µ±½ÓÊÕµ½Ò»¸ö¼üÅÌÖжÏÇëÇóʱ£¬Ëü¶ÁÈ¡¼üÅ̵Ä״̬£¨ÄǾÍÊÇ inb(0x64)µÄÄ¿µÄ£©ºÍɨÃèÂ룬Ҳ¾ÍÊǼüÅÌ·µ»ØµÄ¼üÖµ¡£È»ºó£¬Ò»µ©ÄÚºËÈÏΪÕâÊÇ·ûºÏÌõ¼þµÄ£¬ËüÔËÐÐ got_charÈ¥¸ø³ö²Ù×÷µÄ¼ü£¨É¨ÃèÂëµÄÍ·7¸ö룩ºÍÊÇ°´Ï¼ü£¨É¨ÃèÂëµÄµÚ8λΪ0£© »¹Êǵ¯Æð¼ü£¨É¨ÃèÂëµÄµÚ8λΪ1£©¡£
Example 12-1. intrpt.c
/*
* intrpt.c - An interrupt handler.
*
* Copyright (C) 2001 by Peter Jay Salzman
*/
/*
* The necessary header files
*/
/*
* Standard in kernel modules
*/
#include
#include
#include
#include
#include
#include
#define MY_WORK_QUEUE_NAME "WQsched.c"
static struct workqueue_struct *my_workqueue;
/*
* This will get called by the kernel as soon as it's safe
* to do everything normally allowed by kernel modules.
*/
static void got_char(void *scancode)
{
printk("Scan Code %x %s.\n",
(int)*((char *)scancode) & 0x7F,
*((char *)scancode) & 0x80 ? "Released" : " Pressed" );
}
/*
* This function services keyboard interrupts. It reads the relevant
* information from the keyboard and then puts the non time critical
* part into the work queue. This will be run when the kernel considers it safe.
*/
irqreturn_t irq_handler(int irq, void *dev_id, struct pt_regs *regs)
{
/*
* This variables are static because they need to be
* accessible (through pointers) to the bottom half routine.
*/
static int initialised = 0;
static unsigned char scancode;
static struct work_struct task;
unsigned char status;
/*
* Read keyboard status
*/
status = inb(0x64);
scancode = inb(0x60);
if (initialised == 0) {
INIT_WORK(&task, got_char, &scancode);
initialised = 1;
} else {
PREPARE_WORK(&task, got_char, &scancode);
}
queue_work(my_workqueue, &task);
return IRQ_HANDLED;
}
/*
* Initialize the module - register the IRQ handler
*/
int init_module()
{
my_workqueue = create_workqueue(MY_WORK_QUEUE_NAME);
/*
* Since the keyboard handler won't co-exist with another handler,
* such as us, we have to disable it (free its IRQ) before we do
* anything. Since we don't know where it is, there's no way to
* reinstate it later - so the computer will have to be rebooted
* when we're done.
*/
free_irq(1, NULL);
/*
* Request IRQ 1, the keyboard IRQ, to go to our irq_handler.
* SA_SHIRQ means we're willing to have othe handlers on this IRQ.
* SA_INTERRUPT can be used to make the handler into a fast interrupt.
*/
return request_irq(1, /* The number of the keyboard IRQ on PCs */
irq_handler, /* our handler */
SA_SHIRQ, "test_keyboard_irq_handler",
(void *)(irq_handler));
}
/*
* Cleanup
*/
void cleanup_module()
{
/*
* This is only here for completeness. It's totally irrelevant, since
* we don't have a way to restore the normal keyboard interrupt so the
* computer is completely useless and has to be rebooted.
*/
free_irq(1, NULL);
}
/*
* some work_queue related functions are just available to GPL licensed Modules
*/
MODULE_LICENSE("GPL" );
Notes
[1] ÕâÊÇLinuxÆðÔ´µÄIntel¼Ü¹¹Öеıê×¼µÄÆðÃû·½·¨¡£
[2] ÕâÀïÊÇÒëÕ߸ø³öµÄ¹ØÓÚ¡°bottom half¡±µÄÒ»µã½âÊÍ£¬À´Ô´ÊÇgoogleÉÏËÑË÷µ½µÄÓ¢ÎÄ×ÊÁÏ£º
¡°µ×²¿¡±£¬¡°bottom half¡±³£ÔÚÉæ¼°ÖжϵÄÉ豸Çý¶¯ÖÐÌáµ½¡£
µ±Äں˽ÓÊÕµ½Ò»¸öÖжÏÇëÇ󣬶ÔÓ¦µÄÉ豸Çý¶¯±»µ÷Óá£ÒòΪÔÚÕâ¶Îʱ¼äÄÚÎÞ·¨´¦Àí±ðµÄÈκÎÊÂÎñ£¬ ÈÃÖжϴ¦Àí¾¡¿ìµÄÍê³É²¢ÖØÐÂÈÃÄں˷µ»ØÕý³£µÄ¹¤×÷״̬ÊǷdz£ÖØÒªµÄ¡£¾ÍÊÇÒòΪÕâ¸öÉè¼Æ˼Ï룬 Çý¶¯µÄ¡°¶¥²¿¡±ºÍ¡°µ×²¿¡±µÄ¸ÅÄî±»Ìá³ö£º¡°¶¥²¿¡±ÊDZ»Äں˵÷ÓÃʱ×îÏȱ»Ö´ÐеIJ¿·Ö£¬ ¿ìËÙµÄÍê³ÉһЩ¾¡Á¿ÉÙµÄÈ´ÊDZØÐèµÄ¹¤×÷£¨Ïñ¶ÔÓ²¼þ»òÆäËü×ÊÔ´µÄ¶ÀÏí·ÃÎÊÕâÖÖ±ØÐëÁ¢¿ÌÖ´ÐеIJÙ×÷£©£¬ È»ºó×öһЩÉèÖÃÈᰵײ¿¡±È¥Íê³ÉÄÇЩҪÇóʱ¼äÏà¶Ô±È½Ï¿íÔ£µÄ£¬Ê£ÏµĹ¤×÷¡£
¡°µ×²¿¡±Ê²Ã´Ê±ºòÈçºÎÔË×÷ÊÇÄں˵ÄÉè¼ÆÎÊÌâ¡£ÄãÒ²Ðí»áÌýµ½¡°µ×²¿¡±µÄÉè¼ÆÒѾÔÚ×î½üµÄÄÚºËÖб»·Ï³ýÁË¡£ ÕâÖÖ˵·¨²»ÊǺÜÈ·ÇУ¬ÔÚÐÂÄÚºËÖÐÆäʵÄã¿ÉÒÔȥѡÔñÔõÑùÈ¥Ö´ÐУºÏñÈíÖжϻòÈÎÎñ£¬¾ÍÏñËüÃÇÒÔÇ°ÄÇÑù£¬ »¹ÊǼÓÈëÈÎÎñ¶ÓÁУ¬¸üÏñÆô¶¯Ò»¸öÓû§½ø³Ì¡£
[3] queue_task_irq±»Ò»¸öÈ«¾ÖµÄËø£¨ÓÐËø¶¨×÷ÓõıäÁ¿£© ±£»¤×Å£¬ÔÚ°æ±¾2.2ÖУ¬²¢Ã»ÓÐqueue_task_irq¶øÇÒqueue_task Ò²ÊDZ»Ò»¸öËø±£»¤µÄ¡£
febspeolal ÓÚ 2006-11-09 01:12:10·¢±í:
Chapter 11. Scheduling Tasks
/* We're doing kernel work */
/* Specifically, a module */
/* Necessary because we use the proc fs */
/* We scheduale tasks here */
/* We need to put ourselves to sleep
/* For __init and __exit */
/* For irqreturn_t */
ÈÎÎñµ÷¶È
¾³£ÎÒÃÇÒª¶¨Æڵijé¿Õ´¦ÀíһЩ¡°¼ÒÎñ»î¡±¡£Èç¹ûÕâÑùµÄÈÎÎñͨ¹ýÒ»¸öÓû§½ø³ÌÍê³ÉµÄ£¬ÄÇôÎÒÃÇ¿ÉÒÔ½«Ëü·Åµ½Ò»¸ö crontabÎļþÖС£Èç¹ûÊÇͨ¹ýÒ»¸öÄÚºËÄ£¿éÀ´Íê³É£¬ÄÇôÎÒÃÇÓÐÁ½ÖÖÑ¡Ôñ¡£ µÚÒ»ÖÖÑ¡ÔñÊÇʹÓÃcrontabÎļþ£¬Æô¶¯Ò»¸ö½ø³Ì£¬Í¨¹ýÒ»¸öϵͳµ÷Óû½ÐÑÄÚºËÄ£¿é£¬ÀýÈç´ò¿ªÒ»¸öÎļþ¡£ ÕâºÜûЧÂÊ¡£ÎÒÃÇͨ¹ýcrontabÉú³ÉÁËÒ»¸öнø³Ì£¬¶ÁÈ¡ÁËÒ»¶ÎеĿÉÖ´ÐдúÂë½øÈëÄڴ棬 Ö»ÊÇΪÁË»½ÐÑÒ»¸öÒѾÔÚÄÚ´æÖеÄÄÚºËÄ£¿é¡£
µÚ¶þÖÖÑ¡ÔñÊÇÎÒÃǹ¹ÔìÒ»¸öº¯Êý£¬È»ºó¸Ãº¯ÊýÔÚÿ´Îʱ¼äÖжϷ¢Éúʱ±»µ÷Óá£ÊµÏÖ·½·¨ÊÇÎÒÃǹ¹ÔìÒ»¸öÈÎÎñ£¬Ê¹ÓýṹÌå tq_struct£¬¶ø¸Ã½á¹¹ÌåÓÖ±£´æ×ÅÖ¸Ïò¸Ãº¯ÊýµÄÖ¸Õ롣Ȼºó£¬ÎÒÃÇÓà queue_task°Ñ¸ÃÈÎÎñ·ÅÔÚ½Ð×ötq_timerÈÎÎñ¶ÓÁÐÖС£ ¸Ã¶ÓÁÐÊǽ«ÔÚϸöʱ¼äÖжϷ¢ÉúʱִÐеÄÈÎÎñ¡£ÒòΪÎÒÃÇÏëҪʹËü²»Í£µÄÖ´ÐУ¬ËùÒÔµ±¸Ãº¯ÊýÖ´ÐÐÍêºóÎÒÃÇ»¹Òª½«Ëü·Å»Ø tq_timerÈÎÎñ¶ÓÁÐÖеȴýÏÂÒ»´Îʱ¼äÖжϡ£
µ«ÎÒÃÇËƺõÍüÁËÒ»µã¡£µ±Ò»¸öÄ£¿éÓÃrmmodжÔØʱ£¬Ëü»á¼ì²éʹÓüÆÊý¡£ Èç¹û¸Ã¼ÆÊýΪÁ㣬Ôòµ÷ÓÃmodule_cleanup¡£È»ºó£¬Ä£¿é¾ÍͬËüµÄËùÓк¯Êýµ÷ÓôÓÄÚ´æÖÐÏûʧÁË¡£ ´ËʱûÈËÈ¥¼ì²éÈÎÎñ¶ÓÁÐÖÐÊÇ·ñÕýºÃ»¹ÓÐÒ»¸öµÈ´ýÖ´ÐеÄÕâЩº¯ÊýµÄÖ¸Õë¡£ÔÚ¿ÉÄÜÊÇÒ»¶ÎÂþ³¤µÄʱ¼äºó £¨µ±È»ÊÇÏà¶Ô¼ÆËã»ú¶øÑÔ£¬¶ÔÓÚÎÒÃÇÕâµãʱ¼äʲô¶¼²»ÊÇ£¬Ò²¾Í²î²»¶à°Ù·ÖÖ®Ò»Ãë°É£©£¬ Äں˽ÓÊÕµ½Ò»¸öʱ¼äÖжϣ¬È»ºó×¼±¸µ÷ÓÃÄǸöÔÚÈÎÎñ¶ÓÁÐÖеĺ¯Êý¡£²»ÐÒµÄÊÇ£¬¸Ãº¯ÊýÒѾ²»´æÔÚÁË¡£ ´ó¶àÊýÇé¿öÏ£¬ÓÉÓÚ·ÃÎʵÄÄÚ´æÒ³Êǿհ׵ģ¬ÄãÖ»»áÊÕµ½Ò»¸ö²»Óä¿ìµÄÏûÏ¢¡£µ«ÊÇÈç¹ûÆäËüµÄһЩ´úÂëÇ¡ºÃ¾ÍÔÚÄÇÀ ½á¹û¿ÉÄܽ«»á·Ç³£Ôã¸â¡£Í¬Ñù²»ÐÒµÄÊÇ£¬ÎÒÃÇҲûÓÐÒ»ÖÖÇáÒ×µÄÏòÈÎÎñ¶ÓÁÐ×¢ÏúÈÎÎñµÄ»úÖÆ¡£
¼ÈÈ»cleanup_module²»ÄÜ·µ»ØÒ»¸ö´íÎó´úÂ루ËüÊÇÒ»¸övoidº¯Êý£©£¬ ½â¾öÖ®µÀÊÇÈÃËü²»Òª·µ»Ø¡£Ïà·´£¬µ÷ÓÃsleep_on»òmodule_sleep_on [1]Èà rmmodµÄ½ø³ÌÐÝÃß¡£ÔÚ´Ë֮ǰ£¬Ëü֪ͨ±»Ê±¼äÖжϵ÷¶È³öÈÎÎñ¶ÓÁеÄÄǸöº¯Êý²»ÒªÔÚ·µ»Ø¶ÓÁС£ ÕâÑù£¬ÔÚÏÂÒ»¸öʱ¼äÖжϷ¢Éúʱ£¬rmmod¾Í»á±»»½ÐÑ£¬´ËʱÎÒÃǵĺ¯ÊýÒѾ²»ÔÚ¶ÓÁÐÖУ¬ ¿ÉÒԺܰ²È«µÄжÔØÎÒÃǵÄÄ£¿éÁË¡£
Example 11-1. sched.c
/*
* sched.c - scheduale a function to be called on every timer interrupt.
*
* Copyright (C) 2001 by Peter Jay Salzman
*/
/*
* The necessary header files
*/
/*
* Standard in kernel modules
*/
#include
#include
#include
#include
#include
and wake up later */
#include
#include
struct proc_dir_entry *Our_Proc_File;
#define PROC_ENTRY_FILENAME "sched"
#define MY_WORK_QUEUE_NAME "WQsched.c"
/*
* The number of times the timer interrupt has been called so far
*/
static int TimerIntrpt = 0;
static void intrpt_routine(void *);
static int die = 0; /* set this to 1 for shutdown */
/*
* The work queue structure for this task, from workqueue.h
*/
static struct workqueue_struct *my_workqueue;
static struct work_struct Task;
static DECLARE_WORK(Task, intrpt_routine, NULL);
/*
* This function will be called on every timer interrupt. Notice the void*
* pointer - task functions can be used for more than one purpose, each time
* getting a different parameter.
*/
static void intrpt_routine(void *irrelevant)
{
/*
* Increment the counter
*/
TimerIntrpt++;
/*
* If cleanup wants us to die
*/
if (die == 0)
queue_delayed_work(my_workqueue, &Task, 100);
}
/*
* Put data into the proc fs file.
*/
ssize_t
procfile_read(char *buffer,
char **buffer_location,
off_t offset, int buffer_length, int *eof, void *data)
{
int len; /* The number of bytes actually used */
/*
* It's static so it will still be in memory
* when we leave this function
*/
static char my_buffer[80];
static int count = 1;
/*
* We give all of our information in one go, so if the anybody asks us
* if we have more information the answer should always be no.
*/
if (offset > 0)
return 0;
/*
* Fill the buffer and get its length
*/
len = sprintf(my_buffer, "Timer called %d times so far\n", TimerIntrpt);
count++;
/*
* Tell the function which called us where the buffer is
*/
*buffer_location = my_buffer;
/*
* Return the length
*/
return len;
}
/*
* Initialize the module - register the proc file
*/
int __init init_module()
{
int rv = 0;
/*
* Put the task in the work_timer task queue, so it will be executed at
* next timer interrupt
*/
my_workqueue = create_workqueue(MY_WORK_QUEUE_NAME);
queue_delayed_work(my_workqueue, &Task, 100);
Our_Proc_File = create_proc_entry(PROC_ENTRY_FILENAME, 0644, NULL);
Our_Proc_File->read_proc = procfile_read;
Our_Proc_File->owner = THIS_MODULE;
Our_Proc_File->mode = S_IFREG | S_IRUGO;
Our_Proc_File->uid = 0;
Our_Proc_File->gid = 0;
Our_Proc_File->size = 80;
if (Our_Proc_File == NULL) {
rv = -ENOMEM;
remove_proc_entry(PROC_ENTRY_FILENAME, &proc_root);
printk(KERN_INFO "Error: Could not initialize /proc/%s\n",
PROC_ENTRY_FILENAME);
}
return rv;
}
/*
* Cleanup
*/
void __exit cleanup_module()
{
/*
* Unregister our /proc file
*/
remove_proc_entry(PROC_ENTRY_FILENAME, &proc_root);
printk(KERN_INFO "/proc/%s removed\n", PROC_ENTRY_FILENAME);
die = 1; /* keep intrp_routine from queueing itself */
cancel_delayed_work(&Task); /* no "new ones" */
flush_workqueue(my_workqueue); /* wait till all "old ones" finished */
destroy_workqueue(my_workqueue);
/*
* Sleep until intrpt_routine is called one last time. This is
* necessary, because otherwise we'll deallocate the memory holding
* intrpt_routine and Task while work_timer still references them.
* Notice that here we don't allow signals to interrupt us.
*
* Since WaitQ is now not NULL, this automatically tells the interrupt
* routine it's time to die.
*/
}
/*
* some work_queue related functions
* are just available to GPL licensed Modules
*/
MODULE_LICENSE("GPL" );
Notes
[1] ËüÃÇʵ¼ÊÉÏÊÇÒ»»ØÊ¡£
febspeolal ÓÚ 2006-11-09 01:11:48·¢±í:
Chapter 10. Replacing Printks
/* For current */
/* For the tty declarations */
/* For LINUX_VERSION_CODE */
/* For fg_console, MAX_NR_CONSOLES */
/* For KDSETLED */
/* For vc_cons */
Table of Contents
Ìæ»»printk
ÈÃÄãµÄ¼üÅÌָʾµÆÉÁÆðÀ´
Ìæ»»printk
ÔÚthe Section called ʹÓà X´øÀ´µÄÎÊÌâ in Chapter 1ÖУ¬ ÎÒ˵¹ý×îºÃ²»ÒªÔÚXÖнøÐÐÄÚºËÄ£¿é±à³Ì¡£ÔÚÕæÕýµÄÄÚºËÄ£¿é¿ª·¢ÖеÄÈ·ÊÇÕâÑù¡£ µ«ÔÚʵ¼ÊÓ¦ÓÃÖУ¬ÄãÏëÔÚÈκμÓÔØÄ£¿éµÄtty[1]ÖÕ¶ËÖÐÏÔʾÐÅÏ¢¡£
ʵÏֵķ½·¨ÊÇʹÓÃcurrentÖ¸Õ룬һ¸öÖ¸Ïòµ±Ç°ÔËÐнø³ÌµÄÖ¸Õ룬À´»ñÈ¡µ±Ç°ÈÎÎñµÄ ttyÖն˵ĽṹÌ塣Ȼºó£¬ÎÒÃÇÕÒµ½ÔÚ¸Ãtty½á¹¹ÌåÖÐ ÓÃÀ´ÏòttyдÈë×Ö·ûÐÅÏ¢µÄº¯ÊýµÄÖ¸Õ롣ͨ¹ýÖ¸ÕëÎÒÃÇʹÓøú¯ÊýÀ´ÏòÖÕ¶ËдÈëÐÅÏ¢¡£
Example 10-1. print_string.c
/*
* print_string.c - Send output to the tty we're running on, regardless if it's
* through X11, telnet, etc. We do this by printing the string to the tty
* associated with the current task.
*/
#include
#include
#include
#include
#include
#include
MODULE_LICENSE("GPL" );
MODULE_AUTHOR(" Peter Jay Salzman" );
static void print_string(char *str)
{
struct tty_struct *my_tty;
/*
* tty struct went into signal struct in 2.6.6
*/
#if ( LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,5) )
/*
* The tty for the current task
*/
my_tty = current->tty;
#else
/*
* The tty for the current task, for 2.6.6+ kernels
*/
my_tty = current->signal->tty;
#endif
/*
* If my_tty is NULL, the current task has no tty you can print to
* (ie, if it's a daemon). If so, there's nothing we can do.
*/
if (my_tty != NULL) {
/*
* my_tty->driver is a struct which holds the tty's functions,
* one of which (write) is used to write strings to the tty.
* It can be used to take a string either from the user's or
* kernel's memory segment.
*
* The function's 1st parameter is the tty to write to,
* because the same function would normally be used for all
* tty's of a certain type. The 2nd parameter controls whether
* the function receives a string from kernel memory (false, 0)
* or from user memory (true, non zero). The 3rd parameter is
* a pointer to a string. The 4th parameter is the length of
* the string.
*/
((my_tty->driver)->write) (my_tty, /* The tty itself */
0, /* Don't take the string
from user space */
str, /* String */
strlen(str)); /* Length */
/*
* ttys were originally hardware devices, which (usually)
* strictly followed the ASCII standard. In ASCII, to move to
* a new line you need two characters, a carriage return and a
* line feed. On Unix, the ASCII line feed is used for both
* purposes - so we can't just use \n, because it wouldn't have
* a carriage return and the next line will start at the
* column right after the line feed.
*
* This is why text files are different between Unix and
* MS Windows. In CP/M and derivatives, like MS-DOS and
* MS Windows, the ASCII standard was strictly adhered to,
* and therefore a newline requirs both a LF and a CR.
*/
((my_tty->driver)->write) (my_tty, 0, "\015\012", 2);
}
}
static int __init print_string_init(void)
{
print_string("The module has been inserted. Hello world!" );
return 0;
}
static void __exit print_string_exit(void)
{
print_string("The module has been removed. Farewell world!" );
}
module_init(print_string_init);
module_exit(print_string_exit);
Notes
[1] Teletype, ÔÏÈÊÇÒ»ÖÖÓÃÀ´ºÍUnixϵͳ½»»¥µÄ¼üÅ̺ʹòÓ¡»ú½áºÏÆðÀ´µÄ×°Öá£ÏÖÔÚ£¬ËüÖ»ÊÇÒ»¸öÓÃÀ´Í¬Unix»òÀàËƵÄϵͳ½»Á÷ÎÄ×ÖÁ÷ µÄ³éÏóµÄÉ豸£¬¶ø²»¹ÜËü¾ßÌåÊÇÏÔʾÆ÷£¬XÖеÄxterm£¬»¹ÊÇÒ»¸öͨ¹ýtelnetµÄÍøÂçÁ¬½Ó¡£
ÈÃÄãµÄ¼üÅÌָʾµÆÉÁÆðÀ´
ÄãÒ²ÐíÏëÈÃÄãµÄÄ£¿é¸üÖ±½ÓµÄͬÍâ½ç½»Á÷£¬ÄãµÄ¼üÅÌָʾµÆ¾ÍÊÇÒ»¸ö²»´íµÄÑ¡Ôñ¡£Ëü¿ÉÒÔ¼°Ê±ÏÔʾģ¿éµÄ¹¤×÷״̬£¬ ÎüÒýÄãµÄ×¢Ò⣬²¢ÇÒËüÃDz»ÐíÒªÈκÎÉèÖã¬Ê¹ÓÃÆðÀ´Ò²²»ÏñÏòÖն˻ò´ÅÅÌдÈëÐÅÏ¢ÄÇôΣÏÕ¡£
ÏÂÃæµÄÕâ¸öÄ£¿é´úÂëÑÝʾÁËÒ»¸öÏ൱СµÄÄ£¿é£ºµ±±»¼ÓÔØÈëÄÚºËʱ£¬¼üÅÌָʾµÆ¾Í²»Í£µÄÉÁ˸£¬Ö±µ½Ëü±»Ð¶ÔØ¡£
Example 10-2. kbleds.c
/*
* kbleds.c - Blink keyboard leds until the module is unloaded.
*/
#include
#include
#include
#include
#include
#include
MODULE_DESCRIPTION("Example module illustrating the use of Keyboard LEDs.");
MODULE_AUTHOR("Daniele Paolo Scarpazza");
MODULE_LICENSE("GPL");
struct timer_list my_timer;
struct tty_driver *my_driver;
char kbledstatus = 0;
#define BLINK_DELAY HZ/5
#define ALL_LEDS_ON 0x07
#define RESTORE_LEDS 0xFF
/*
* Function my_timer_func blinks the keyboard LEDs periodically by invoking
* command KDSETLED of ioctl() on the keyboard driver. To learn more on virtual
* terminal ioctl operations, please see file:
* /usr/src/linux/drivers/char/vt_ioctl.c, function vt_ioctl().
*
* The argument to KDSETLED is alternatively set to 7 (thus causing the led
* mode to be set to LED_SHOW_IOCTL, and all the leds are lit) and to 0xFF
* (any value above 7 switches back the led mode to LED_SHOW_FLAGS, thus
* the LEDs reflect the actual keyboard status). To learn more on this,
* please see file:
* /usr/src/linux/drivers/char/keyboard.c, function setledstate().
*
*/
static void my_timer_func(unsigned long ptr)
{
int *pstatus = (int *)ptr;
if (*pstatus == ALL_LEDS_ON)
*pstatus = RESTORE_LEDS;
else
*pstatus = ALL_LEDS_ON;
(my_driver->ioctl) (vc_cons[fg_console].d->vc_tty, NULL, KDSETLED,
*pstatus);
my_timer.expires = jiffies + BLINK_DELAY;
add_timer(&my_timer);
}
static int __init kbleds_init(void)
{
int i;
printk(KERN_INFO "kbleds: loading\n");
printk(KERN_INFO "kbleds: fgconsole is %x\n", fg_console);
for (i = 0; i < MAX_NR_CONSOLES; i++) {
if (!vc_cons[i].d)
break;
printk(KERN_INFO "poet_atkm: console[%i/%i] #%i, tty %lx\n", i,
MAX_NR_CONSOLES, vc_cons[i].d->vc_num,
(unsigned long)vc_cons[i].d->vc_tty);
}
printk(KERN_INFO "kbleds: finished scanning consoles\n");
my_driver = vc_cons[fg_console].d->vc_tty->driver;
printk(KERN_INFO "kbleds: tty driver magic %x\n", my_driver->magic);
/*
* Set up the LED blink timer the first time
*/
init_timer(&my_timer);
my_timer.function = my_timer_func;
my_timer.data = (unsigned long)&kbledstatus;
my_timer.expires = jiffies + BLINK_DELAY;
add_timer(&my_timer);
return 0;
}
static void __exit kbleds_cleanup(void)
{
printk(KERN_INFO "kbleds: unloading...\n");
del_timer(&my_timer);
(my_driver->ioctl) (vc_cons[fg_console].d->vc_tty, NULL, KDSETLED,
RESTORE_LEDS);
}
module_init(kbleds_init);
module_exit(kbleds_cleanup);
Èç¹ûÉÏÃæµÄ·½·¨¶¼ÎÞ·¨Âú×ãÄãµ÷ÊÔµÄÐèÒª£¬Äã¾Í¿ÉÄÜÐèÒªÆäËüµÄ¼¼ÇÉÁË¡£»¹¼ÇµÃÄǸöÔÚ make menuconfig ʱµÄCONFIG_LL_DEBUG²ÎÊýÂð£¿Èç¹ûÄ㼤»î¸ÃÑ¡ÏÄã¾Í¿ÉÒÔ»ñµÃ¶Ô´®¿ÚµÄµ×²ã²Ù×Ý¡£Èç¹ûÕâÈÔÈ»²»¹»Ë¬£¬Ä㻹¿ÉÒÔ¶Ô kernel/printk.c»òÆäËüµÄ»ù±¾µÄϵͳµ×²ãµ÷Óôò²¹¶¡À´Ê¹ÓÃprintascii£¬´Ó¶ø¿ÉÒÔͨ¹ý´®¿Ú¸ú×Ù Äں˵Äÿ²½¶¯×÷¡£Èç¹ûÄãµÄ¼Ü¹¹²»Ö§³ÖÉÏÃæµÄÀý×ÓÈ´ÓÐÒ»¸ö±ê×¼µÄ´®¿Ú£¬Õâ¿ÉÄÜÓ¦¸ÃÊÇÄãÊ×ÏÈÓ¦¸Ã¿¼ÂǵÄÁË¡£Í¨¹ýÍøÂçÉ쵀 Öն˵÷ÊÔͬÑùÖµµÃ³¢ÊÔ¡£
¾¡¹ÜÓкܶà¹ØÓÚÈçºÎµ÷ÊԵļ¼ÇÉ£¬µ«ÎÒÒªÌáÐѵÄÊÇÈκε÷ÊÔ¶¼»á´úÂë´øÀ´Ó°Ïì¡£¼ÓÈëµ÷ÊÔ´úÂë×ãÒÔµ¼ÖÂÔʼ´úÂë²úÉúbugµÄ Ìõ¼þµÄÏûʧ£¬ËùÒÔ¾¡¿ÉÄÜÉٵļÓÈëµ÷ÊÔ´úÂë²¢ÇÒÈ·±£ËüÃDz»³öÏÖÔÚ³ÉÊìµÄ´úÂëÖС£
febspeolal ÓÚ 2006-11-09 01:11:23·¢±í:
Chapter 9. Blocking Processes
/* We're doing kernel work */
/* Specifically, a module */
/* Necessary because we use proc fs */
/* For putting processes to sleep and
/* for get_user and put_user */
×èÈû½ø³Ì
Enter Sandman
µ±±ðÈËÈÃÄã×öÒ»¼þÄã²»ÄÜÂíÉÏÈ¥×öµÄÊÂʱ£¬Äã»áÈçºÎ·´Ó³£¿Èç¹ûÄãÊÇÈËÀàµÄ»°£¬¶øÇÒ¶Ô·½Ò²ÊÇÈËÀàµÄ»°£¬ ÄãÖ»»á˵£º¡°ÏÖÔÚ²»ÐУ¬ÎÒæ×ÅÔÚ¡£ÉÁ¿ª£¡¡±µ«ÊÇÈç¹ûÄãÊÇÒ»¸öÄÚºËÄ£¿é¶øÇÒÄã±»Ò»¸ö½ø³ÌÒÔͬÑùµÄÎÊÌâÀ§ÈÅ£¬ Äã»áÓÐÁíÍâÒ»¸öÑ¡Ôñ¡£Äã¿ÉÒÔÈøýø³ÌÐÝÃßÖ±µ½Äã¿ÉÒÔΪËü·þÎñʱ¡£±Ï¾¹£¬ÕâÑùµÄÇé¿öÔÚÄÚºËÖÐʱʱ¿Ì¿Ì¶¼ÔÚ·¢Éú £¨Õâ¾ÍÊÇϵͳÈöà½ø³ÌÔÚµ¥CPUÉÏͬʱÔËÐеķ½·¨£©¡£
Õâ¸öÄÚºËÄ£¿é¾ÍÊÇÒ»¸öÕâÑùµÄÀý×Ó¡£Îļþ£¨/proc/sleep)£©Ö»¿ÉÒÔÔÚͬһʱ¿Ì±»Ò»¸ö½ø³Ì´ò¿ª¡£ Èç¹û¸ÃÎļþÒѾ±»´ò¿ª£¬ÄÚºËÄ£¿é½«µ÷Óú¯Êý wait_event_interruptible[1]¡£¸Ãº¯ÊýÐÞ¸ÄtaskµÄ״̬£¨taskÊÇÒ»¸öÄÚºËÖеĽṹÌåÊý¾Ý½á¹¹£¬ ÆäÖб£´æ×ŶÔÓ¦½ø³ÌµÄÐÅÏ¢ºÍ¸Ã½ø³ÌÕýÔÚµ÷ÓõÄϵͳµ÷Óã¬Èç¹ûÓеĻ°£©Îª TASK_INTERRUPTIBLEÒâζןĽø³Ì½«²»»á¼ÌÐøÔËÐÐÖ±µ½±»»½ÐÑ£¬È»ºó±»Ìí¼Óµ½ÏµÍ³µÄ½ø³ÌµÈ´ý¶ÓÁÐ WaitQÖУ¬Ò»¸öµÈ´ý´ò¿ª¸ÃÎļþµÄ¶ÓÁÐÖС£È»ºó£¬¸Ãº¯Êýµ÷ÓÃϵͳµ÷¶ÈÆ÷È¥Çл»µ½ÁíÒ»¸ö²»Í¬µÄ µ«ÓÐCPUÔËËãÇëÇóµÄ½ø³Ì¡£
µ±Ò»¸ö½ø³Ì´¦ÀíÍê¸ÃÎļþ²¢ÇҹرÕÁ˸ÃÎļþ£¬module_close¾Í±»µ÷ÓÃÖ´ÐÐÁË¡£ ¸Ãº¯Êý»½ÐÑËùÓÐÔڵȴý¶ÓÁÐÖеĽø³Ì£¨»¹Ã»ÓÐÖ»»½ÐÑÌض¨½ø³ÌµÄ»úÖÆ£©¡£È»ºó¸Ãº¯Êý·µ»Ø£¬ ÄǸö¸Õ¸Õ¹Ø±ÕÎļþµÄ½ø³ÌµÃÒÔ¼ÌÐøÔËÐС£¼°Ê±µÄ£¬½ø³Ìµ÷¶ÈÆ÷»áÅж¨¸Ã½ø³ÌÖ´ÐÐÒÑÖ´ÐÐÍê±Ï£¬ ½«CPUתÈøø±ðµÄ½ø³Ì¡£±»ÌṩCPUʹÓÃȨµÄÄǸö½ø³Ì¾ÍÇ¡ºÃ´ÓÏÈǰϵͳµ÷Óà module_interruptible_sleep_on[2]ºóµÄµØ·½¿ªÊ¼¼ÌÐøÖ´ÐС£ Ëü¿ÉÒÔÉèÖÃÒ»¸öÈ«¾Ö±äÁ¿È¥Í¨Öª±ðµÄ½ø³Ì¸ÃÎļþÒѱ»´ò¿ªÕ¼ÓÃÁË¡£µ±±ðµÄÇëÇó¸ÃÎļþµÄ½ø³Ì»ñµÃCPUʱ¼äƬʱ£¬ ËüÃǽ«¼ì²â¸Ã±äÁ¿È»ºó·µ»ØÐÝÃß¡£
¸üÓÐȤµÄÊÇ£¬module_close²¢²»Â¢¶Ï»½ÐѵȴýÖеÄÇëÇóÎļþµÄ½ø³ÌµÄȨÁ¦¡£Ò»¸öÐźţ¬ÏñCtrl+c (SIGINTÒ²Äܹ»»½ÐѱðµÄ½ø³Ì [3]¡£ ÔÚÕâÖÖÇé¿öÏ£¬ÎÒÃÇÏëÁ¢¼´·µ»Ø-EINTR ¡£ Õâ¶ÔÓû§ºÜÖØÒª£¬¾Ù¸öÀý×ÓÀ´Ëµ£¬Óû§¿ÉÒÔÔÚij¸ö½ø³Ì½ÓÊܵ½ÎļþÇ°ÖÕÖ¹¸Ã½ø³Ì¡£
»¹ÓÐÒ»µãÖµµÃ×¢Òâ¡£ÓÐЩʱºò½ø³Ì²¢²»Ô¸ÒâÐÝÃߣ¬ËüÃÇҪôÁ¢¼´Ö´ÐÐËüÃÇÏë×öµÄ£¬ Ҫô±»¸æÖªÈÎÎñÎÞ·¨½øÐС£ÕâÑùµÄ½ø³ÌÔÚ´ò¿ªÎļþʱ»áʹÓñêÖ¾O_NONBLOCK¡£ ÔÚ±ðµÄ½ø³Ì±»×èÈûʱÄÚºËÓ¦¸Ã×ö³öµÄÏìÓ¦ÊÇ·µ»Ø´íÎó´úÂë-EAGAIN£¬ÏñÔÚ±¾ÀýÖжԸÃÎļþµÄÇëÇóµÄ½ø³Ì¡£³ÌÐò cat_noblock£¬ÔÚ±¾ÕµÄÔ´´úÂëĿ¼Ï¿ÉÒÔÕÒµ½£¬¾ÍÄܹ»Ê¹Óñê־λ O_NONBLOCK´ò¿ªÎļþ¡£
Example 9-1. sleep.c
/*
* sleep.c - create a /proc file, and if several processes try to open it at
* the same time, put all but one to sleep
*/
#include
#include
#include
#include
waking them up */
#include
/*
* The module's file functions
*/
/*
* Here we keep the last message received, to prove that we can process our
* input
*/
#define MESSAGE_LENGTH 80
static char Message[MESSAGE_LENGTH];
static struct proc_dir_entry *Our_Proc_File;
#define PROC_ENTRY_FILENAME "sleep"
/*
* Since we use the file operations struct, we can't use the special proc
* output provisions - we have to use a standard read function, which is this
* function
*/
static ssize_t module_output(struct file *file, /* see include/linux/fs.h */
char *buf, /* The buffer to put data to
(in the user segment) */
size_t len, /* The length of the buffer */
loff_t * offset)
{
static int finished = 0;
int i;
char message[MESSAGE_LENGTH + 30];
/*
* Return 0 to signify end of file - that we have nothing
* more to say at this point.
*/
if (finished) {
finished = 0;
return 0;
}
/*
* If you don't understand this by now, you're hopeless as a kernel
* programmer.
*/
sprintf(message, "Last input:%s\n", Message);
for (i = 0; i < len && message[i]; i++)
put_user(message[i], buf + i);
finished = 1;
return i; /* Return the number of bytes "read" */
}
/*
* This function receives input from the user when the user writes to the /proc
* file.
*/
static ssize_t module_input(struct file *file, /* The file itself */
const char *buf, /* The buffer with input */
size_t length, /* The buffer's length */
loff_t * offset)
{ /* offset to file - ignore */
int i;
/*
* Put the input into Message, where module_output will later be
* able to use it
*/
for (i = 0; i < MESSAGE_LENGTH - 1 && i < length; i++)
get_user(Message[i], buf + i);
/*
* we want a standard, zero terminated string
*/
Message[i] = '\0';
/*
* We need to return the number of input characters used
*/
return i;
}
/*
* 1 if the file is currently open by somebody
*/
int Already_Open = 0;
/*
* Queue of processes who want our file
*/
DECLARE_WAIT_QUEUE_HEAD(WaitQ);
/*
* Called when the /proc file is opened
*/
static int module_open(struct inode *inode, struct file *file)
{
/*
* If the file's flags include O_NONBLOCK, it means the process doesn't
* want to wait for the file. In this case, if the file is already
* open, we should fail with -EAGAIN, meaning "you'll have to try
* again", instead of blocking a process which would rather stay awake.
*/
if ((file->f_flags & O_NONBLOCK) && Already_Open)
return -EAGAIN;
/*
* This is the correct place for try_module_get(THIS_MODULE) because
* if a process is in the loop, which is within the kernel module,
* the kernel module must not be removed.
*/
try_module_get(THIS_MODULE);
/*
* If the file is already open, wait until it isn't
*/
while (Already_Open) {
int i, is_sig = 0;
/*
* This function puts the current process, including any system
* calls, such as us, to sleep. Execution will be resumed right
* after the function call, either because somebody called
* wake_up(&WaitQ) (only module_close does that, when the file
* is closed) or when a signal, such as Ctrl-C, is sent
* to the process
*/
wait_event_interruptible(WaitQ, !Already_Open);
/*
* If we woke up because we got a signal we're not blocking,
* return -EINTR (fail the system call). This allows processes
* to be killed or stopped.
*/
/*
* Emmanuel Papirakis:
*
* This is a little update to work with 2.2.*. Signals now are contained in
* two words (64 bits) and are stored in a structure that contains an array of
* two unsigned longs. We now have to make 2 checks in our if.
*
* Ori Pomerantz:
*
* Nobody promised me they'll never use more than 64 bits, or that this book
* won't be used for a version of Linux with a word size of 16 bits. This code
* would work in any case.
*/
for (i = 0; i < _NSIG_WORDS && !is_sig; i++)
is_sig =
current->pending.signal.sig[i] & ~current->
blocked.sig[i];
if (is_sig) {
/*
* It's important to put module_put(THIS_MODULE) here,
* because for processes where the open is interrupted
* there will never be a corresponding close. If we
* don't decrement the usage count here, we will be
* left with a positive usage count which we'll have no
* way to bring down to zero, giving us an immortal
* module, which can only be killed by rebooting
* the machine.
*/
module_put(THIS_MODULE);
return -EINTR;
}
}
/*
* If we got here, Already_Open must be zero
*/
/*
* Open the file
*/
Already_Open = 1;
return 0; /* Allow the access */
}
/*
* Called when the /proc file is closed
*/
int module_close(struct inode *inode, struct file *file)
{
/*
* Set Already_Open to zero, so one of the processes in the WaitQ will
* be able to set Already_Open back to one and to open the file. All
* the other processes will be called when Already_Open is back to one,
* so they'll go back to sleep.
*/
Already_Open = 0;
/*
* Wake up all the processes in WaitQ, so if anybody is waiting for the
* file, they can have it.
*/
wake_up(&WaitQ);
module_put(THIS_MODULE);
return 0; /* success */
}
/*
* This function decides whether to allow an operation (return zero) or not
* allow it (return a non-zero which indicates why it is not allowed).
*
* The operation can be one of the following values:
* 0 - Execute (run the "file" - meaningless in our case)
* 2 - Write (input to the kernel module)
* 4 - Read (output from the kernel module)
*
* This is the real function that checks file permissions. The permissions
* returned by ls -l are for reference only, and can be overridden here.
*/
static int module_permission(struct inode *inode, int op, struct nameidata *nd)
{
/*
* We allow everybody to read from our module, but only root (uid 0)
* may write to it
*/
if (op == 4 || (op == 2 && current->euid == 0))
return 0;
/*
* If it's anything else, access is denied
*/
return -EACCES;
}
/*
* Structures to register as the /proc file, with pointers to all the relevant
* functions.
*/
/*
* File operations for our proc file. This is where we place pointers to all
* the functions called when somebody tries to do something to our file. NULL
* means we don't want to deal with something.
*/
static struct file_operations File_Ops_4_Our_Proc_File = {
.read = module_output, /* "read" from the file */
.write = module_input, /* "write" to the file */
.open = module_open, /* called when the /proc file is opened */
.release = module_close, /* called when it's closed */
};
/*
* Inode operations for our proc file. We need it so we'll have somewhere to
* specify the file operations structure we want to use, and the function we
* use for permissions. It's also possible to specify functions to be called
* for anything else which could be done to an inode (although we don't bother,
* we just put NULL).
*/
static struct inode_operations Inode_Ops_4_Our_Proc_File = {
.permission = module_permission, /* check for permissions */
};
/*
* Module initialization and cleanup
*/
/*
* Initialize the module - register the proc file
*/
int init_module()
{
int rv = 0;
Our_Proc_File = create_proc_entry(PROC_ENTRY_FILENAME, 0644, NULL);
Our_Proc_File->owner = THIS_MODULE;
Our_Proc_File->proc_iops = &Inode_Ops_4_Our_Proc_File;
Our_Proc_File->proc_fops = &File_Ops_4_Our_Proc_File;
Our_Proc_File->mode = S_IFREG | S_IRUGO | S_IWUSR;
Our_Proc_File->uid = 0;
Our_Proc_File->gid = 0;
Our_Proc_File->size = 80;
if (Our_Proc_File == NULL) {
rv = -ENOMEM;
remove_proc_entry(PROC_ENTRY_FILENAME, &proc_root);
printk(KERN_INFO "Error: Could not initialize /proc/test\n" );
}
return rv;
}
/*
* Cleanup - unregister our file from /proc. This could get dangerous if
* there are still processes waiting in WaitQ, because they are inside our
* open function, which will get unloaded. I'll explain how to avoid removal
* of a kernel module in such a case in chapter 10.
*/
void cleanup_module()
{
remove_proc_entry(PROC_ENTRY_FILENAME, &proc_root);
}
Notes
[1] ×î·½±ãµÄ±£³Öij¸öÎļþ±»´ò¿ªµÄ·½·¨ÊÇʹÓÃÃüÁî tail -f´ò¿ª¸ÃÎļþ¡£
[2] Õâ¾ÍÒâζןýø³ÌÈÔÈ»ÔÚÄÚºË̬ÖУ¬ ¸Ã½ø³ÌÒѾµ÷ÓÃÁËopenµÄϵͳµ÷Ó㬵«ÏµÍ³µ÷ÓÃȴûÓзµ»Ø¡£ ÔÚÕâ¶Îʱ¼äÄڸýø³Ì½«²»»áµÃÖª±ðÈËÕýÔÚʹÓÃCPU¡£
[3] ÕâÊÇÒòΪÎÒÃÇʹÓõÄÊÇmodule_interruptible_sleep_on¡£ÎÒÃÇÒ²¿ÉÒÔʹÓà module_sleep_on£¬µ«ÕâÑù»áµ¼ÖÂһЩʮ·Ö·ßŵÄÓû§£¬ÒòΪËûÃǵÄCtrl+c½«²»ÆðÈκÎ×÷Óá£
febspeolal ÓÚ 2006-11-09 01:11:01·¢±í:
Chapter 8. System Calls
¡£
/* We're doing kernel work */
/* Specifically, a module, */
/* which will have params */
/* The list of system calls */
ϵͳµ÷ÓÃ
µ½Ä¿Ç°ÎªÖ¹£¬ÎÒÃÇËù×öµÄÖ»ÊÇʹÓÃÍêÉƵÄÄں˻úÖÆ×¢²á/procÎļþºÍ´¦ÀíÉ豸µÄ¶ÔÏó¡£Èç¹ûÖ»ÊÇÏëдһ¸öÉ豸Çý¶¯£¬ ÕâЩÄں˳ÌÐòÔ±É趨µÄ·½Ê½ÒѾ×ã¹»ÁË¡£µ«ÊÇ£¬Äã²»Ïë×öһЩ²»Ñ°³£µÄÊÂÂ𣬠ÏëʹÄãµÄϵͳ¿´ÆðÀ´²»Ò»ÑùÂ𣿵±È»£¬ÕâÈ¡¾öÄã×Ô¼º¡£
ÕâÀï¿ÉÊÇÒ»¸öΣÏյĵط½¡£ÏÂÃæµÄÕâ¸öÀý×ÓÖУ¬ÎҹرÕÁËϵͳµ÷Óà open()¡£ÕâÒâζ×ÅÎÒÎÞ·¨´ò¿ªÈκÎÎļþ£¬Ö´ÐÐÈκγÌÐò£¬Á¬Ê¹Óà shutdown¹Ø»ú¶¼²»ÐУ¬¹Ø»úÖ»ÄÜ¿¿ÞôµçÔ´°´Å¥ÁË¡£ÐÒÔ˵Ļ°£¬²»»áÓÐÎļþ¶ªÊ§¡£ Òª±£Ö¤²»¶ªÊ§ÎļþµÄ»°£¬ÔÚinsmodºÍ rmmod֮ǰÇëÖ´ÐÐsyncÃüÁî¡£
±ð¹Üʲô/procÎļþºÍʲôÉ豸ÎļþÁË£¬ ËüÃÇÖ»ÊÇСµÄϸ½ÚÎÊÌâ¡£ËùÓнø³ÌͬÄں˴ò½»µÀµÄ¸ù±¾·½Ê½ÊÇϵͳµ÷Óᣠµ±Ò»¸ö½ø³ÌÐèÒªÄÚºËÌṩijÏî·þÎñʱ£¨Ïñ´ò¿ªÒ»¸öÎļþ£¬Éú³ÉÒ»¸öнø³Ì£¬»òÒªÇó¸ü¶àµÄÄڴ棩£¬ ¾Í»á·¢Éúϵͳµ÷Óá£Èç¹ûÄãÏëÄãµÄϵͳÔË×÷·½Ê½¿´ÆðÀ´ÓÐÒâ˼µã£¬Õâ¾ÍÊÇÄ㶯Êֵĵط½¡£ ˳±ã˵һ¾ä£¬Èç¹ûÄãÏëÖªµÀû¸ö³ÌÐòʹÓÃÁËÄÄЩϵͳµ÷Óã¬ÔËÐÐstrace
×ܵÄÀ´Ëµ£¬Ò»¸öÓû§½ø³ÌÊDz»Ó¦¸ÃÒ²²»Äܹ»Ö±½Ó·ÃÎÊÄں˵ġ£Ëü²»ÄÜ·ÃÎÊÄں˵ÄÄڴ棬 Ò²²»Äܵ÷ÓÃÄں˵ĺ¯Êý¡£ÕâÊÇCPUµÄÓ²¼þ±£»¤»úÖƾö¶¨µÄ£¨ÕâÒ²ÊÇΪʲô½Ð×ö¡°±£»¤Ä£Ê½¡±µÄÔÒò£©¡£
ϵͳµ÷ÓÃÊÇÕâÌõ¹æÔòµÄÀýÍâ¡£Ëù·¢ÉúµÄÊÂÊÇÒ»¸ö½ø³ÌÓúÏÊʵÄÖµÌî³ä¼Ä´æÆ÷£¬ È»ºóµ÷ÓÃÒ»ÌõÌøתµ½Òѱ»¶¨Òå¹ýµÄÄÚºËÖеÄλÖõÄÖ¸Áµ±È»£¬ÕâЩ¶¨Òå¹ýµÄλÖÃÊǶÔÓÚÓû§½ø³Ì¿É¶ÁµÄ£¬ µ«ÊÇÏÔÈ»ÊDz»¿ÉдµÄ£©¡£ÔÚIntel¼Ü¹¹ÖУ¬ÕâÊÇͨ¹ý 0x80 ÖжÏÍê³ÉµÄ¡£Ó²¼þÃ÷°×Ò»µ©ÄãÌøתµ½Õâ¸öλÖ㬠Äã¾Í²»ÔÙÊÇÔÚ´¦´¦ÊÜÏÞµÄÓû§Ì¬ÖÐÔËÐÐÁË£¬¶øÊÇÔÚÎÞËù²»ÄܵÄÄÚºË̬ÖС£
ÄÚºËÖеĽø³Ì¿ÉÒÔÌøת¹ýÈ¥µÄλÖýÐ×öϵͳµ÷Óá£ÄǶù½«¼ì²éϵͳµ÷ÓõÄÐòºÅ£¬ ÕâЩÐòºÅ½«¸æËßÄÚºËÓû§½ø³ÌÐèҪʲôÑùµÄ·þÎñ¡£È»ºó£¬Í¨¹ý²éÕÒϵͳµ÷Óñí( sys_call_table) ÕÒµ½Äں˺¯ÊýµÄµØÖ·£¬µ÷Óøú¯Êý¡£µ±º¯Êý·µ»Øʱ£¬ ÔÙ×öһЩϵͳ¼ì²é£¬½Óמͷµ»ØÓû§½ø³Ì£¨»òÊÇÁíÒ»¸ö½ø³Ì£¬Èç¹û¸Ã½ø³ÌµÄʱ¼äÓÃÍêÁË£©¡£ Èç¹ûÄãÏëÔĶÁÒ»ÏÂÕâ·½ÃæµÄÔ´´úÂ룬ËüÃǾÍÔÚÎļþ arch/$<$architecture$>$/kernel/entry.SÖÐ ENTRY(system_call)ÐеÄÏÂÃæ¡£
ËùÒÔ£¬Èç¹ûÎÒÃÇÏë¸Ä±äij¸öϵͳµ÷ÓõÄÔË×÷·½Ê½£¬ÎÒÃÇÖ»ÐèÒªÓÃÎÒÃÇ×Ô¼ºµÄº¯ÊýȥʵÏÖËü (ͨ³£Ö»ÊǼÓÒ»µãÎÒÃÇ×Ô¼ºµÄ´úÂ룬Ȼºóµ÷ÓÃÔº¯Êý)È»ºó¸Ä±äϵͳµ÷Óñí (sys_call_table)ÖеÄÖ¸ÕëֵʹËüÖ¸ÏòÎÒÃǵĺ¯Êý¡£ÒòΪÕâЩģ¿é½«ÔÚÒÔºóжÔØ£¬ ÎÒÃDz»ÏëϵͳÒò´Ë¶ø²»Îȶ¨£¬ËùÒÔcleanup_moduleÖлָ´ÏµÍ³µ÷ÓñíÊǷdz£ÖØÒªµÄ¡£
Õâ¾ÍÊÇÕâÑùµÄÒ»¸öÄ£¿é¡£ÎÒÃÇ¿ÉÒÔ¡°¼àÊÓ¡±Ò»¸öÌض¨µÄÓû§£¬È»ºóʹÓà printk()Êä³ö¸ÃÓû§´ò¿ªµÄÿ¸öÎļþµÄÏûÏ¢¡£ÔÚ½áÊøÇ°£¬ÎÒÃÇÓÃ×Ô¼ºµÄ our_sys_openº¯ÊýÌæ»»ÁË´ò¿ªÎļþµÄϵͳµ÷Ó᣸ú¯Êý¼ì²éµ±Ç°½ø³ÌµÄÓû§ÐòºÅ£¨uid£¬user's id£©£¬ Èç¹ûÆ¥ÅäÎÒÃǼàÊÓµÄÓû§µÄÐòºÅ£¬Ëüµ÷ÓÃprintk()Êä³ö½«Òª´ò¿ªµÄÎļþµÄÃû×Ö¡£ Òª²»È»£¬¾ÍÓÃͬÑùµÄ²ÎÊýµ÷ÓÃÔʼµÄopen()º¯Êý£¬ÕæÕýµÄ´ò¿ªÎļþ¡£
º¯Êýinit_module¸Ä±äÁËϵͳµ÷ÓñíÖеÄÇ¡µ±Î»ÖõÄֵȻºóÓÃÒ»¸ö±äÁ¿±£´æÏÂÀ´¡£º¯Êý cleanup_moduleÔòʹÓøñäÁ¿½«ËùÓж«Î÷»¹Ô¡£ÕâÖÖ´¦Àí·½·¨ÆäʵÊǺÜΣÏյġ£ÏëÏóһϣ¬ Èç¹ûÎÒÃÇÓÐÁ½¸öÕâÑùµÄÄ£¿é£¬AºÍB¡£AÓÃA_openÌæ»»ÁËϵͳµÄsys_openº¯Êý£¬¶øBÓÃB_open¡£ÏÖÔÚ£¬ÎÒÃÇÏÈ°ÑÄ£¿éA¼ÓÔØ£¬ ÄÇôÔÏȵÄϵͳµ÷Óñ»A_openÌæ´úÁË£¬A_openÔÚÍê³É¹¤×÷ºó×ÔÉíÓÖ»áµ÷ÓÃÔʼµÄsys_openº¯Êý ¡£½Ó×Å£¬ÎÒÃǼÓÔØBÄ£¿é£¬ ËüÓÃB_open¸ü¸ÄÁËÏÖÔÚµÄÒѸü¸ÄΪA_open£¨ÏÔÈ»ËüÈÏΪÊÇÔʼµÄsys_openϵͳµ÷Ó㩵Äϵͳµ÷Óá£
ÏÖÔÚ£¬Èç¹ûBÏÈжÔØ£¬Ò»ÇÐÕý³£¡£ÏµÍ³µ÷ÓûỹԵ½A_open£¬¶øA_openÓÖ»áµ÷ÓÃÔʼµÄsys_open¡£ µ«ÊÇ£¬Ò»µ©AÏÈжÔØ£¬ÏµÍ³¾Í»á±ÀÀ£¡£AµÄжÔػὫϵͳµ÷Óû¹Ôµ½ÔʼµÄsys_open£¬°ÑB´ÓÁ´ÖÐÇжϡ£ ´ËʱÔÙжÔØB£¬B»á½«ÏµÍ³µ÷Óûָ´µ½ËüÈÏΪµÄ³õʼ״̬£¬Ò²¾ÍÊÇA_open£¬µ«A_openÒѾ²»ÔÚÄÚ´æÖÐÁË¡£ Õ§Ò»¿´À´£¬ÎÒÃÇËƺõ¿ÉÒÔͨ¹ý¼ì²âϵͳµ÷ÓÃÊÇ·ñÓëÎÒÃǵÄopenº¯ÊýÏàͬ£¬Èç¹û²»ÏàͬÔòʲô¶¼²»×ö £¨ÕâÑùB¾Í²»»á³¢ÊÔÔÚжÔØʱ»Ö¸´ÏµÍ³µ÷ÓÃ±í£©¡£µ«ÆäʵÕâÑù¸üÔã¡£µ±AÏȱ»Ð¶ÔØʱ£¬Ëü½«¼ì²âµ½ÏµÍ³ µ÷ÓÃÒѱ»¸ü¸ÄΪB_open£¬ËùÒÔA½«²»»áÔÚжÔØʱ»Ö¸´ÏµÍ³µ÷ÓñíÖÐÏàÓ¦µÄÏî¡£´Ëʱ²»ÐÒµÄÊ·¢ÉúÁË£¬ B_open½«ÈÔÈ»µ÷ÓÃÒѾ²»´æÔÚµÄA_open£¬ÕâÑù¼´Ê¹Ä㲻жÔØBÄ£¿é£¬ÏµÍ³Ò²±ÀÀ£ÁË¡£
µ«ÊÇÕâÖÖÌ滻ϵͳµ÷Óõķ½·¨ÊÇÎ¥±³ÕýʽӦÓÃÖÐϵͳµÄÎȶ¨ºÍ¿É¿¿ÔÔòµÄ¡£ËùÒÔ£¬ÎªÁË·ÀֹDZÔڵĶÔϵͳµ÷Óñí Ð޸ĴøÀ´µÄΣº¦£¬ÏµÍ³µ÷Óñísys_call_table²»ÔÙ±»Äں˵¼³ö¡£ÕâÒâζ×ÅÈç¹ûÄãÏë˳ÀûµÄÔËÐÐÕâ¸öÀý×Ó£¬Äã±ØÐëΪÄãµÄ ÄÚºËÊ÷´ò²¹¶¡À´µ¼³ösys_call_table£¬ÔÚexampleĿ¼ÄÚÄ㽫ÕÒµ½Ïà¹ØµÄ²¹¶¡ºÍ˵Ã÷¡£ÕýÈçͬÄãÏëÏñµÄÄÇÑù£¬Õâ¿É²»ÊÇ ¶ùÏ·£¬Èç¹ûÄãµÄϵͳ·Ç³£±¦¹ó(ÀýÈçÕâ²»ÊÇÄãµÄϵͳ£¬»òϵͳºÜÄѻָ´)£¬Äã×îºÃ»¹ÊÇ·ÅÆú¡£Èç¹ûÄãÈÔÈ»¼á³Ö£¬ÎÒ¿ÉÒÔ ¸æËßÄãµÄÊÇ´ò²¹¶¡ËäÈ»²»»áÓжà´óÎÊÌ⣬µ«ÄÚºËά»¤ÕßËûÃǿ϶¨ÓÐ×ã¹»µÄÀíÓÉÔÚ2.6ÄÚºËÖв»Ö§³ÖÕâÖÖhack¡£ÏêÇéÇë²Î¿¼README¡£ Èç¹ûÄãÑ¡ÔñÁËN£¬Ìø¹ýÕâ¸öÀý×ÓÊÇÒ»¸ö°²È«µÄÑ¡Ôñ¡£
Example 8-1. syscall.c
/*
* syscall.c
*
* System call "stealing" sample.
*/
/*
* Copyright (C) 2001 by Peter Jay Salzman
*/
/*
* The necessary header files
*/
/*
* Standard in kernel modules
*/
#include
#include
#include
#include
/*
* For the current (process) structure, we need
* this to know who the current user is.
*/
#include
#include
/*
* The system call table (a table of functions). We
* just define this as external, and the kernel will
* fill it up for us when we are insmod'ed
*
* sys_call_table is no longer exported in 2.6.x kernels.
* If you really want to try this DANGEROUS module you will
* have to apply the supplied patch against your current kernel
* and recompile it.
*/
extern void *sys_call_table[];
/*
* UID we want to spy on - will be filled from the
* command line
*/
static int uid;
module_param(uid, int, 0644);
/*
* A pointer to the original system call. The reason
* we keep this, rather than call the original function
* (sys_open), is because somebody else might have
* replaced the system call before us. Note that this
* is not 100% safe, because if another module
* replaced sys_open before us, then when we're inserted
* we'll call the function in that module - and it
* might be removed before we are.
*
* Another reason for this is that we can't get sys_open.
* It's a static variable, so it is not exported.
*/
asmlinkage int (*original_call) (const char *, int, int);
/*
* The function we'll replace sys_open (the function
* called when you call the open system call) with. To
* find the exact prototype, with the number and type
* of arguments, we find the original function first
* (it's at fs/open.c).
*
* In theory, this means that we're tied to the
* current version of the kernel. In practice, the
* system calls almost never change (it would wreck havoc
* and require programs to be recompiled, since the system
* calls are the interface between the kernel and the
* processes).
*/
asmlinkage int our_sys_open(const char *filename, int flags, int mode)
{
int i = 0;
char ch;
/*
* Check if this is the user we're spying on
*/
if (uid == current->uid) {
/*
* Report the file, if relevant
*/
printk("Opened file by %d: ", uid);
do {
get_user(ch, filename + i);
i++;
printk("%c", ch);
} while (ch != 0);
printk("\n" );
}
/*
* Call the original sys_open - otherwise, we lose
* the ability to open files
*/
return original_call(filename, flags, mode);
}
/*
* Initialize the module - replace the system call
*/
int init_module()
{
/*
* Warning - too late for it now, but maybe for
* next time...
*/
printk("I'm dangerous. I hope you did a " );
printk("sync before you insmod'ed me.\n" );
printk("My counterpart, cleanup_module(), is even" );
printk("more dangerous. If\n" );
printk("you value your file system, it will " );
printk("be \"sync; rmmod\" \n" );
printk("when you remove this module.\n" );
/*
* Keep a pointer to the original function in
* original_call, and then replace the system call
* in the system call table with our_sys_open
*/
original_call = sys_call_table[__NR_open];
sys_call_table[__NR_open] = our_sys_open;
/*
* To get the address of the function for system
* call foo, go to sys_call_table[__NR_foo].
*/
printk("Spying on UID:%d\n", uid);
return 0;
}
/*
* Cleanup - unregister the appropriate file from /proc
*/
void cleanup_module()
{
/*
* Return the system call back to normal
*/
if (sys_call_table[__NR_open] != our_sys_open) {
printk("Somebody else also played with the " );
printk("open system call\n" );
printk("The system may be left in " );
printk("an unstable state.\n" );
}
sys_call_table[__NR_open] = original_call;
}
febspeolal ÓÚ 2006-11-09 01:10:36·¢±í:
Chapter 7. Talking To Device Files
/* We're doing kernel work */
/* Specifically, a module */
/* for get_user and put_user */
/* open */
/* exit */
/* ioctl */
ÓëÉ豸Îļþ¶Ô»° (writes and IOCTLs)
É豸ÎļþÊÇÓÃÀ´´ú±íÏà¶ÔÓ¦µÄÓ²¼þÉ豸¡£¾ø´ó¶àÊýµÄÓ²¼þÉ豸ÊÇÓÃÀ´½øÐÐÊä³öºÍÊäÈë²Ù×÷µÄ£¬ ËùÒÔÔÚÄÚºËÖп϶¨ÓÐÄں˴ӽø³ÌÖлñµÃ·¢Ë͵½É豸µÄÊä³öµÄ»úÖÆ¡£ÕâÊÇͨ¹ý´ò¿ªÒ»¸öÉ豸ÎļþÈ»ºó ÏòÆäÖнøÐÐд²Ù×÷À´ÊµÏֵģ¬Èçͬ¶ÔÆÕͨÎļþµÄд²Ù×÷¡£ÔÚÏÂÃæµÄµÄÀý×ÓÖУ¬ÕâÊÇͨ¹ý device_writeʵÏֵġ£
µ«Õâ²¢²»×ÜÊǹ»Óá£ÉèÏëÄãÓÐÒ»¸öͨ¹ý´®¿ÚÁ¬½ÓµÄµ÷Öƽâµ÷Æ÷(¼´Ê¹ÄãʹÓõÄÊÇÄÚÖõ÷Öƽâµ÷Æ÷£¬ ¶ÔÓÚCPUÀ´ËµÍ¬ÑùÒ²ÊÇͨ¹ýÁ¬½ÓÔÚ´®¿ÚÉÏÀ´ÊµÏÖ¹¤×÷µÄ£©¡£Í¨³£ÎÒÃÇͨ¹ý´ò¿ªÒ»¸öÉ豸ÎļþÏòµ÷Öƽâµ÷Æ÷ ·¢ËÍÐÅÏ¢£¨½«ÒªÍ¨¹ýͨÐÅÏß·´«ÊäµÄÖ¸Áî»òÊý¾Ý£©»ò¶ÁÈ¡ÐÅÏ¢£¨´ÓͨÐÅÏß·Öзµ»ØµÄÏìÓ¦Ö¸Áî»òÊý¾Ý£©¡£ µ«ÊÇ£¬ÎÒÃÇÈçºÎÉèÖÃͬ´®¿Ú¶Ô»°µÄËÙÂÊ£¬Ò²¾ÍÊÇÏò´®¿Ú´«ÊäÊý¾ÝµÄËÙÂÊÕâ¸öÎÊÌâÈÔȻûÓнâ¾ö¡£
½â¾öÖ®µÀÊÇÔÚUnixϵͳÖеĺ¯Êýioctl(Input Output ConTroLµÄ¼òд)¡£ ÿ¸öÉ豸¿ÉÒÔÓÐ×Ô¼ºµÄioctlÃüÁͨ¹ý¶ÁÈ¡ioctl's ¿ÉÒÔ´Ó½ø³ÌÖÐÏòÄں˷¢ËÍÐÅÏ¢£¬»òдioctl'sÏò½ø³Ì·µ»ØÐÅÏ¢ [1]£¬»òÕßÁ½Õ߶¼ÊÇ£¬»ò¶¼²»ÊÇ¡£º¯Êýioctl µ÷ÓÃʱÐèÒªÈý¸ö²ÎÊý£ººÏÊʵÄÉ豸ÎļþµÄÎļþÃèÊö·û£¬ioctlºÅ£¬ºÍÒ»¸ö¿ÉÒÔ±»Ò»¸öÈÎÎñʹÓÃÀ´ ´«µÝÈκζ«Î÷µÄlongÀàÐ͵IJÎÊý[2]
ioctlºÅÊÇ·´Ó³Ö÷É豸ºÅ£¬ioctlµÄÖÖÀ࣬¶ÔÓ¦µÄÃüÁîºÍ²ÎÊýÀàÐ͵ÄÊý×Ö¡£Ëüͨ³£ÊÇͨ¹ýÔÚÍ·ÎļþÖкêµ÷Óà (_IO, _IOR, _IOW »ò_IOWR£¬È¡¾öÓÚÆäÖÖÀà)À´½¨Á¢µÄ¡£¸ÃÍ·ÎļþÓ¦¸Ã±»Ê¹Óà ioctlµÄÓû§³ÌÐò°üº¬£¨ÕâÑùËüÃǾͿÉÒÔÉú³ÉÕýÈ·µÄioctl's£© ºÍÄÚºËÇý¶¯Ä£¿é°üº¬£¨ÕâÑùÄ£¿é²ÅÄÜÀí½âËü£©¡£ÔÚÏÂÃæµÄÀý×ÓÖУ¬Í·ÎļþΪchardev.h£¬Ô´³ÌÐòΪioctl.c¡£
¼´Ê¹ÄãÖ»ÏëÔÚ×Ô¼ºµÄÄ£¿éÖÐʹÓÃioctls£¬Äã×îºÃ»¹ÊǽÓÊÕÕýʽµÄ ioctl±ê×¼£¬ÕâÑùµ±ÄãÒâÍâµÄʹÓñðÈ˵Äioctls£¬ »ò±ðÈËʹÓÃÄãµÄʱ£¬Äã»áÖªµÀÓдíÎó·¢Éú¡£ÏêÇé²Î¼ûÄں˴úÂëĿ¼Ê÷ϵÄÎļþ Documentation/ioctl-number.txt.
Example 7-1. chardev.c
/*
* chardev.c - Create an input/output character device
*/
#include
#include
#include
#include
#include "chardev.h"
#define SUCCESS 0
#define DEVICE_NAME "char_dev"
#define BUF_LEN 80
/*
* Is the device open right now? Used to prevent
* concurent access into the same device
*/
static int Device_Open = 0;
/*
* The message the device will give when asked
*/
static char Message[BUF_LEN];
/*
* How far did the process reading the message get?
* Useful if the message is larger than the size of the
* buffer we get to fill in device_read.
*/
static char *Message_Ptr;
/*
* This is called whenever a process attempts to open the device file
*/
static int device_open(struct inode *inode, struct file *file)
{
#ifdef DEBUG
printk("device_open(%p)\n", file);
#endif
/*
* We don't want to talk to two processes at the same time
*/
if (Device_Open)
return -EBUSY;
Device_Open++;
/*
* Initialize the message
*/
Message_Ptr = Message;
try_module_get(THIS_MODULE);
return SUCCESS;
}
static int device_release(struct inode *inode, struct file *file)
{
#ifdef DEBUG
printk("device_release(%p,%p)\n", inode, file);
#endif
/*
* We're now ready for our next caller
*/
Device_Open--;
module_put(THIS_MODULE);
return SUCCESS;
}
/*
* This function is called whenever a process which has already opened the
* device file attempts to read from it.
*/
static ssize_t device_read(struct file *file, /* see include/linux/fs.h */
char __user * buffer, /* buffer to be
* filled with data */
size_t length, /* length of the buffer */
loff_t * offset)
{
/*
* Number of bytes actually written to the buffer
*/
int bytes_read = 0;
#ifdef DEBUG
printk("device_read(%p,%p,%d)\n", file, buffer, length);
#endif
/*
* If we're at the end of the message, return 0
* (which signifies end of file)
*/
if (*Message_Ptr == 0)
return 0;
/*
* Actually put the data into the buffer
*/
while (length && *Message_Ptr) {
/*
* Because the buffer is in the user data segment,
* not the kernel data segment, assignment wouldn't
* work. Instead, we have to use put_user which
* copies data from the kernel data segment to the
* user data segment.
*/
put_user(*(Message_Ptr++), buffer++);
length--;
bytes_read++;
}
#ifdef DEBUG
printk("Read %d bytes, %d left\n", bytes_read, length);
#endif
/*
* Read functions are supposed to return the number
* of bytes actually inserted into the buffer
*/
return bytes_read;
}
/*
* This function is called when somebody tries to
* write into our device file.
*/
static ssize_t
device_write(struct file *file,
const char __user * buffer, size_t length, loff_t * offset)
{
int i;
#ifdef DEBUG
printk("device_write(%p,%s,%d)", file, buffer, length);
#endif
for (i = 0; i < length && i < BUF_LEN; i++)
get_user(Message[i], buffer + i);
Message_Ptr = Message;
/*
* Again, return the number of input characters used
*/
return i;
}
/*
* This function is called whenever a process tries to do an ioctl on our
* device file. We get two extra parameters (additional to the inode and file
* structures, which all device functions get): the number of the ioctl called
* and the parameter given to the ioctl function.
*
* If the ioctl is write or read/write (meaning output is returned to the
* calling process), the ioctl call returns the output of this function.
*
*/
int device_ioctl(struct inode *inode, /* see include/linux/fs.h */
struct file *file, /* ditto */
unsigned int ioctl_num, /* number and param for ioctl */
unsigned long ioctl_param)
{
int i;
char *temp;
char ch;
/*
* Switch according to the ioctl called
*/
switch (ioctl_num) {
case IOCTL_SET_MSG:
/*
* Receive a pointer to a message (in user space) and set that
* to be the device's message. Get the parameter given to
* ioctl by the process.
*/
temp = (char *)ioctl_param;
/*
* Find the length of the message
*/
get_user(ch, temp);
for (i = 0; ch && i < BUF_LEN; i++, temp++)
get_user(ch, temp);
device_write(file, (char *)ioctl_param, i, 0);
break;
case IOCTL_GET_MSG:
/*
* Give the current message to the calling process -
* the parameter we got is a pointer, fill it.
*/
i = device_read(file, (char *)ioctl_param, 99, 0);
/*
* Put a zero at the end of the buffer, so it will be
* properly terminated
*/
put_user('\0', (char *)ioctl_param + i);
break;
case IOCTL_GET_NTH_BYTE:
/*
* This ioctl is both input (ioctl_param) and
* output (the return value of this function)
*/
return Message[ioctl_param];
break;
}
return SUCCESS;
}
/* Module Declarations */
/*
* This structure will hold the functions to be called
* when a process does something to the device we
* created. Since a pointer to this structure is kept in
* the devices table, it can't be local to
* init_module. NULL is for unimplemented functions.
*/
struct file_operations Fops = {
.read = device_read,
.write = device_write,
.ioctl = device_ioctl,
.open = device_open,
.release = device_release, /* a.k.a. close */
};
/*
* Initialize the module - Register the character device
*/
int init_module()
{
int ret_val;
/*
* Register the character device (atleast try)
*/
ret_val = register_chrdev(MAJOR_NUM, DEVICE_NAME, &Fops);
/*
* Negative values signify an error
*/
if (ret_val < 0) {
printk("%s failed with %d\n",
"Sorry, registering the character device ", ret_val);
return ret_val;
}
printk("%s The major device number is %d.\n",
"Registeration is a success", MAJOR_NUM);
printk("If you want to talk to the device driver,\n" );
printk("you'll have to create a device file. \n" );
printk("We suggest you use:\n" );
printk("mknod %s c %d 0\n", DEVICE_FILE_NAME, MAJOR_NUM);
printk("The device file name is important, because\n" );
printk("the ioctl program assumes that's the\n" );
printk("file you'll use.\n" );
return 0;
}
/*
* Cleanup - unregister the appropriate file from /proc
*/
void cleanup_module()
{
int ret;
/*
* Unregister the device
*/
ret = unregister_chrdev(MAJOR_NUM, DEVICE_NAME);
/*
* If there's an error, report it
*/
if (ret < 0)
printk("Error in module_unregister_chrdev: %d\n", ret);
}
Example 7-2. chardev.h
/*
* chardev.h - the header file with the ioctl definitions.
*
* The declarations here have to be in a header file, because
* they need to be known both to the kernel module
* (in chardev.c) and the process calling ioctl (ioctl.c)
*/
#ifndef CHARDEV_H
#define CHARDEV_H
#include
/*
* The major device number. We can't rely on dynamic
* registration any more, because ioctls need to know
* it.
*/
#define MAJOR_NUM 100
/*
* Set the message of the device driver
*/
#define IOCTL_SET_MSG _IOR(MAJOR_NUM, 0, char *)
/*
* _IOR means that we're creating an ioctl command
* number for passing information from a user process
* to the kernel module.
*
* The first arguments, MAJOR_NUM, is the major device
* number we're using.
*
* The second argument is the number of the command
* (there could be several with different meanings).
*
* The third argument is the type we want to get from
* the process to the kernel.
*/
/*
* Get the message of the device driver
*/
#define IOCTL_GET_MSG _IOR(MAJOR_NUM, 1, char *)
/*
* This IOCTL is used for output, to get the message
* of the device driver. However, we still need the
* buffer to place the message in to be input,
* as it is allocated by the process.
*/
/*
* Get the n'th byte of the message
*/
#define IOCTL_GET_NTH_BYTE _IOWR(MAJOR_NUM, 2, int)
/*
* The IOCTL is used for both input and output. It
* receives from the user a number, n, and returns
* Message[n].
*/
/*
* The name of the device file
*/
#define DEVICE_FILE_NAME "char_dev"
#endif
Example 7-3. ioctl.c
/*
* ioctl.c - the process to use ioctl's to control the kernel module
*
* Until now we could have used cat for input and output. But now
* we need to do ioctl's, which require writing our own process.
*/
/*
* device specifics, such as ioctl numbers and the
* major device file.
*/
#include "chardev.h"
#include
#include
#include
/*
* Functions for the ioctl calls
*/
ioctl_set_msg(int file_desc, char *message)
{
int ret_val;
ret_val = ioctl(file_desc, IOCTL_SET_MSG, message);
if (ret_val < 0) {
printf("ioctl_set_msg failed:%d\n", ret_val);
exit(-1);
}
}
ioctl_get_msg(int file_desc)
{
int ret_val;
char message[100];
/*
* Warning - this is dangerous because we don't tell
* the kernel how far it's allowed to write, so it
* might overflow the buffer. In a real production
* program, we would have used two ioctls - one to tell
* the kernel the buffer length and another to give
* it the buffer to fill
*/
ret_val = ioctl(file_desc, IOCTL_GET_MSG, message);
if (ret_val < 0) {
printf("ioctl_get_msg failed:%d\n", ret_val);
exit(-1);
}
printf("get_msg message:%s\n", message);
}
ioctl_get_nth_byte(int file_desc)
{
int i;
char c;
printf("get_nth_byte message:" );
i = 0;
while (c != 0) {
c = ioctl(file_desc, IOCTL_GET_NTH_BYTE, i++);
if (c < 0) {
printf
("ioctl_get_nth_byte failed at the %d'th byte:\n",
i);
exit(-1);
}
putchar(c);
}
putchar('\n');
}
/*
* Main - Call the ioctl functions
*/
main()
{
int file_desc, ret_val;
char *msg = "Message passed by ioctl\n";
file_desc = open(DEVICE_FILE_NAME, 0);
if (file_desc < 0) {
printf("Can't open device file: %s\n", DEVICE_FILE_NAME);
exit(-1);
}
ioctl_get_nth_byte(file_desc);
ioctl_get_msg(file_desc);
ioctl_set_msg(file_desc, msg);
close(file_desc);
}
Notes
[1] ×¢ÒâÕâ¶ù¡°¶Á¡±Ó롰д¡±µÄ½ÇÉ«Ôٴηת¹ýÀ´£¬ÔÚioctl'sÖжÁÊÇÏòÄں˷¢ËÍÐÅÏ¢£¬ ¶øдÊÇ´ÓÄں˻ñÈ¡ÐÅÏ¢¡£
[2] ÕâÑùµÄ±íÊö²¢²»×¼È·¡£ ÀýÈçÄã²»ÄÜÔÚioctlÖд«µÝÒ»¸ö½á¹¹Ì壬µ«Äã¿ÉÒÔͨ¹ý´«µÝÖ¸ÏòÕâ¸ö½á¹¹ÌåµÄÖ¸ÕëʵÏÖ¡£
febspeolal ÓÚ 2006-11-09 01:10:11·¢±í:
Chapter 6. Using /proc For Input
/* We're doing kernel work */
/* Specifically, a module */
/* Necessary because we use proc fs */
/* for get_user and put_user */
ʹÓà /proc ×÷ΪÊäÈë
ÏÖÔÚÎÒÃÇÓÐÁ½ÖÖ´ÓÄÚºËÄ£¿é»ñµÃÊä³öµÄ·½·¨£ºÎÒÃÇ¿ÉÒÔ×¢²áÒ»¸öÉ豸Çý¶¯²¢Óà mknodÉú³ÉÒ»¸öÉ豸Îļþ£¬»òÕßÎÒÃÇ¿ÉÒÔ½¨Á¢Ò»¸ö /procÎļþ¡£ÕâÑùÄں˾ͿÉÒÔ¸æËßÎÒÃÇÖØÒªµÄÐÅÏ¢¡£ ʣϵÄΨһÎÊÌâÊÇÎÒÃÇû·¨·´À¡ÐÅÏ¢¡£µÚÒ»ÖÖ·½·¨ÊÇÏò/procÎļþϵͳдÈëÐÅÏ¢¡£
ÓÉÓÚ /proc ÎļþϵͳÊÇΪÄÚºËÊä³öÆäÔËÐÐÐÅÏ¢¶øÉè¼ÆµÄ£¬Ëü²¢Î´ÏòÄÚºËÊäÈëÐÅÏ¢ÌṩÁËÈκÎ×¼±¸¡£ ½á¹¹Ìåstruct proc_dir_entry²¢Ã»ÓÐÖ¸ÏòÊäÈ뺯ÊýµÄÖ¸Õ룬¶øÊÇÖ¸ÏòÁËÒ»¸öÊä³öº¯Êý¡£ ×÷ΪÌæ´ú°ì·¨£¬Ïò/proc дÈëÐÅÏ¢£¬ÎÒÃÇ¿ÉÒÔʹÓñê×¼µÄÎļþϵͳÌṩµÄ»úÖÆ¡£
ÔÚLinuxÖÐÓÐÒ»ÖÖ±ê×¼µÄ×¢²áÎļþϵͳµÄ·½·¨¡£¼ÈȻÿÖÖÎļþϵͳ¶¼±ØÐëÓд¦ÀíÎļþ Ë÷Òý½ÚµãinodeºÍÎļþ±¾ÉíµÄº¯Êý[1], ÄÇô¾ÍÒ»¶¨ÓÐÖֽṹÌåÈ¥´æ·ÅÕâЩº¯ÊýµÄÖ¸Õë¡£Õâ¾ÍÊǽṹÌåstruct inode_operations£¬ ËüÆäÖÐÓÖ°üº¬Ò»¸öÖ¸Ïò½á¹¹Ìåstruct file_operationsµÄÖ¸Õë¡£ÔÚ /proc ÎļþϵͳÖУ¬ µ±ÎÒÃÇÐèҪע²áÒ»¸öÐÂÎļþʱ£¬ÎÒÃDZ»ÔÊÐíÑ¡ÔñÄÄÒ»¸östruct inode_operations ½á¹¹Ìå¡£Õâ¾ÍÊÇÎÒÃǽ«Ê¹ÓõĻúÖÆ£¬Óðüº¬½á¹¹Ìå struct inode_operationsÖ¸ÕëµÄ½á¹¹Ìåstruct file_operations À´Ö¸ÏòÎÒÃǵÄmodule_inputºÍmodule_outputº¯Êý¡£
ÐèҪעÒâµÄÊÇ¡°¶Á¡±ºÍ¡°Ð´¡±µÄº¬ÒåÔÚÄÚºËÖÐÊÇ·´¹ýÀ´µÄ¡£¡°¶Á¡±Òâζ×ÅÊä³ö£¬¶ø¡°Ð´¡±Òâζ×ÅÊäÈë¡£ ÕâÊÇ´ÓÓû§µÄ½Ç¶ÈÀ´¿´´ýÎÊÌâµÄ¡£Èç¹ûÒ»¸ö½ø³ÌÖ»ÄÜ´ÓÄں˵ġ°Êä³ö¡±»ñµÃÊäÈ룬 ¶øÄÚºËÒ²ÊÇ´Ó½ø³ÌµÄÊä³öÖеõ½¡°ÊäÈ롱µÄ¡£
ÔÚÕâ¶ùÁíÒ»¼þÓÐȤµÄʾÍÊÇmodule_permissionº¯ÊýÁË¡£¸Ãº¯ÊýÔÚÿ¸ö½ø³ÌÏëÒª¶Ô /procÎļþϵͳÄÚµÄÎļþ²Ù×÷ʱ±»µ÷Óã¬ËüÀ´¾ö¶¨ÊÇ·ñ²Ù×÷±»ÔÊÐí¡£ Ä¿Ç°ËüÖ»ÊǶԲÙ×÷ºÍ²Ù×÷ËùÊôÓû§µÄUID½øÐÐÅжϣ¬µ«Ëü¿ÉÒÔÒ²°ÑÆäËüµÄ¶«Î÷°üÀ¨½øÀ´£¬ Ïñ»¹ÓÐÄÄЩ±ðµÄ½ø³ÌÔÚ¶Ô¸ÃÎļþ½øÐвÙ×÷£¬µ±Ç°µÄʱ¼ä£¬»òÊÇÎÒÃÇ×îºó½ÓÊÕµ½µÄÊäÈë¡£
¼ÓÈëºêput_userºÍget_userµÄÔÒòÊÇ LinuxµÄÄÚ´æÊÇʹÓ÷ÖÒ³»úÖƵģ¨ÔÚIntel¼Ü¹¹ÏÂÊÇÈç´Ë£¬µ«ÆäËü¼Ü¹¹ÏÂÓпÉÄܲ»Í¬£©¡£ Õâ¾ÍÒâζ×ÅÖ¸Õë×ÔÉí²¢²»ÊÇÖ¸ÏòÒ»¸öȷʵµÄÎïÀíÄÚ´æµØÖ·£¬¶øÖªÊÇ·ÖÒ³ÖеÄÒ»¸öµØÖ·£¬ ¶øÇÒÄã±ØÐëÖªµÀÄÄЩ·ÖÒ³½«À´ÊÇ¿ÉÓõġ£ÆäÖÐÄں˱¾ÉíÕ¼ÓÃÒ»¸ö·ÖÒ³£¬ÆäËüµÄÿ¸ö½ø³Ì¶¼ÓÐ×Ô¼ºµÄ·ÖÒ³¡£
½ø³ÌÄÜ¿´µÃµ½µÄ·ÖÒ³Ö»ÓÐÊôÓÚËü×Ô¼ºµÄ£¬ËùÒÔµ±±àдÓû§³ÌÐòʱ£¬²»Óÿ¼ÂÇ·ÖÒ³µÄ´æÔÚ¡£ µ«Êǵ±Äã±àдÄÚºËÄ£¿éʱ£¬Äã¾Í»á·ÃÎÊÓÉϵͳ×Ô¶¯¹ÜÀíµÄÄÚºËËùÔڵķÖÒ³¡£ µ±Ò»¿éÄڴ滺³åÇøÖеÄÄÚÈÝÒªÔÚµ±Ç°ÔËÐÐÖеĽø³ÌºÍÄÚºËÖ®¼ä´«µÝʱ£¬ Äں˵ĺ¯Êý¾Í½ÓÊÕÖ¸ÏòÔÚ½ø³Ì·ÖÒ³ÖеĸÃÄڴ滺³åÇøµÄÖ¸Õë¡£ºêput_userºÍ get_userÔÊÐíÄã½øÐÐÕâÑùµÄ·ÃÎÊÄÚ´æµÄ²Ù×÷¡£
Example 6-1. procfs.c
/*
* procfs.c - create a "file" in /proc, which allows both input and output.
*/
#include
#include
#include
#include
/*
* Here we keep the last message received, to prove
* that we can process our input
*/
#define MESSAGE_LENGTH 80
static char Message[MESSAGE_LENGTH];
static struct proc_dir_entry *Our_Proc_File;
#define PROC_ENTRY_FILENAME "rw_test"
static ssize_t module_output(struct file *filp, /* see include/linux/fs.h */
char *buffer, /* buffer to fill with data */
size_t length, /* length of the buffer */
loff_t * offset)
{
static int finished = 0;
int i;
char message[MESSAGE_LENGTH + 30];
/*
* We return 0 to indicate end of file, that we have
* no more information. Otherwise, processes will
* continue to read from us in an endless loop.
*/
if (finished) {
finished = 0;
return 0;
}
/*
* We use put_user to copy the string from the kernel's
* memory segment to the memory segment of the process
* that called us. get_user, BTW, is
* used for the reverse.
*/
sprintf(message, "Last input:%s", Message);
for (i = 0; i < length && message[i]; i++)
put_user(message[i], buffer + i);
/*
* Notice, we assume here that the size of the message
* is below len, or it will be received cut. In a real
* life situation, if the size of the message is less
* than len then we'd return len and on the second call
* start filling the buffer with the len+1'th byte of
* the message.
*/
finished = 1;
return i; /* Return the number of bytes "read" */
}
static ssize_t
module_input(struct file *filp, const char *buff, size_t len, loff_t * off)
{
int i;
/*
* Put the input into Message, where module_output
* will later be able to use it
*/
for (i = 0; i < MESSAGE_LENGTH - 1 && i < len; i++)
get_user(Message[i], buff + i);
Message[i] = '\0'; /* we want a standard, zero terminated string */
return i;
}
/*
* This function decides whether to allow an operation
* (return zero) or not allow it (return a non-zero
* which indicates why it is not allowed).
*
* The operation can be one of the following values:
* 0 - Execute (run the "file" - meaningless in our case)
* 2 - Write (input to the kernel module)
* 4 - Read (output from the kernel module)
*
* This is the real function that checks file
* permissions. The permissions returned by ls -l are
* for referece only, and can be overridden here.
*/
static int module_permission(struct inode *inode, int op, struct nameidata *foo)
{
/*
* We allow everybody to read from our module, but
* only root (uid 0) may write to it
*/
if (op == 4 || (op == 2 && current->euid == 0))
return 0;
/*
* If it's anything else, access is denied
*/
return -EACCES;
}
/*
* The file is opened - we don't really care about
* that, but it does mean we need to increment the
* module's reference count.
*/
int module_open(struct inode *inode, struct file *file)
{
try_module_get(THIS_MODULE);
return 0;
}
/*
* The file is closed - again, interesting only because
* of the reference count.
*/
int module_close(struct inode *inode, struct file *file)
{
module_put(THIS_MODULE);
return 0; /* success */
}
static struct file_operations File_Ops_4_Our_Proc_File = {
.read = module_output,
.write = module_input,
.open = module_open,
.release = module_close,
};
/*
* Inode operations for our proc file. We need it so
* we'll have some place to specify the file operations
* structure we want to use, and the function we use for
* permissions. It's also possible to specify functions
* to be called for anything else which could be done to
* an inode (although we don't bother, we just put
* NULL).
*/
static struct inode_operations Inode_Ops_4_Our_Proc_File = {
.permission = module_permission, /* check for permissions */
};
/*
* Module initialization and cleanup
*/
int init_module()
{
int rv = 0;
Our_Proc_File = create_proc_entry(PROC_ENTRY_FILENAME, 0644, NULL);
Our_Proc_File->owner = THIS_MODULE;
Our_Proc_File->proc_iops = &Inode_Ops_4_Our_Proc_File;
Our_Proc_File->proc_fops = &File_Ops_4_Our_Proc_File;
Our_Proc_File->mode = S_IFREG | S_IRUGO | S_IWUSR;
Our_Proc_File->uid = 0;
Our_Proc_File->gid = 0;
Our_Proc_File->size = 80;
if (Our_Proc_File == NULL) {
rv = -ENOMEM;
remove_proc_entry(PROC_ENTRY_FILENAME, &proc_root);
printk(KERN_INFO "Error: Could not initialize /proc/test\n");
}
return rv;
}
void cleanup_module()
{
remove_proc_entry(PROC_ENTRY_FILENAME, &proc_root);
}
»¹ÐèÒª¸ü¶àµÄ¹ØÓÚprocfsµÄÀý×Ó£¿ÎÒÒªÌáÐÑÄãµÄÊÇ£ºµÚÒ»£¬ÓÐÏûϢ˵ҲÐí²»¾Ãprocfs½«±»sysfsÈ¡´ú£»µÚ¶þ£¬ Èç¹ûÄãÕæµÄºÜÏë¶àÁ˽âЩprocfs£¬Äã¿ÉÒԲο¼Â·¾¶ linux/Documentation/DocBook/ Ï嵀 ÄÇЩ¼¼ÊõÐÔµÄÎĵµ¡£ÔÚÄں˴úÂëÊ÷¸ùĿ¼ÏÂʹÓà make help À´»ñµÃÈçºÎ½«ÕâЩÎĵµ×ª»¯ÎªÄãÆ«ºÃµÄ¸ñʽ£¬ÀýÈ磺 make htmldocs ¡£Èç¹ûÄãҪΪÄں˼ÓÈëһЩÄãµÄÎĵµ£¬ÄãÒ²Ó¦¸Ã¿¼ÂÇÕâÑù×ö¡£
Notes
[1] Á½ÕßµÄÇø±ðÊÇÎļþµÄ²Ù×÷Õë¶Ô¾ßÌåµÄ£¬ÊµÔÚµÄÎļþ£¬ ¶øÎļþË÷Òý½ÚµãµÄ²Ù×÷ÊÇÕë¶ÔÎļþµÄÒýÓã¬Ïñ½¨Á¢ÎļþµÄÁ¬½ÓµÈ¡£
febspeolal ÓÚ 2006-11-09 01:09:35·¢±í:
Chapter 5. The /proc File System
/* Specifically, a module */
/* We're doing kernel work */
/* Necessary because we use the proc fs */
* directory>/fs/proc/array.c.
¹ØÓÚ /proc Îļþϵͳ
ÔÚLinuxÖÐÓÐÁíÒ»ÖÖÄں˺ÍÄÚºËÄ£¿éÏò½ø³Ì´«µÝÐÅÏ¢µÄ·½·¨£¬ÄǾÍÊÇͨ¹ý /procÎļþϵͳ¡£ËüÔÏÈÉè¼ÆµÄÄ¿µÄÊÇΪ²é¿´½ø³ÌÐÅÏ¢ Ìṩһ¸ö·½±ãµÄ;¾¶£¬ÏÖÔÚËü±»ÓÃÀ´ÏòÓû§Ìṩ¸÷ÖÖÄÚºËÖб»¸ÐÐËȤµÄÄÚÈÝ¡£ÏñÎļþ /proc/modulesÀïÊÇÒѼÓÔØÄ£¿éµÄÁÐ±í£¬Îļþ/proc/meminfo ÀïÊǹØÓÚÄÚ´æʹÓõÄÐÅÏ¢¡£
ʹÓà proc ÎļþϵͳµÄ·½·¨Í¬Ê¹ÓÃÉ豸ÎļþºÜÏàËÆ¡£Ä㽨Á¢Ò»¸ö°üº¬ /procÎļþÐèÒªµÄËùÓÐÐÅÏ¢µÄ½á¹¹Ì壬 ÕâÆäÖаüÀ¨´¦Àí¸÷ÖÖÊÂÎñµÄº¯ÊýµÄÖ¸Õ루ÔÚÎÒÃǵÄÀý×ÓÖУ¬Ö»Óõ½´Ó/procÎļþ¶ÁÈ¡ÐÅÏ¢µÄº¯Êý£©¡£È»ºóÔÚinit_module ʱÏòÄÚºË×¢²áÕâ¸ö½á¹¹Ì壬ÔÚcleanup_moduleʱעÏúÕâ¸ö½á¹¹Ìå¡£
ÎÒÃÇʹÓÃproc_register_dynamic[1]µÄÔÒòÊÇÎÒÃDz»ÓÃÈ¥ÉèÖÃinode£¬¶øÁô¸ø ÄÚºËÈ¥×Ô¶¯·ÖÅä´Ó¶ø±ÜÃâϵͳ³åÍ»´íÎó¡£ ÆÕͨµÄÎļþϵͳÊǽ¨Á¢ÔÚ´ÅÅÌÉϵģ¬¶ø /proc µÄÎļþ½ö½öÊǽ¨Á¢ÔÚÄÚ´æÖеġ£ ÔÚÇ°ÖÖÇé¿öÖУ¬inodeµÄÊýÖµÊÇÒ»¸öÖ¸Ïò´æ´¢ÔÚ´ÅÅÌij¸öλÖõÄÎļþµÄË÷Òý½Úµã£¨inode¾ÍÊÇindex-nodeµÄËõд£©¡£ ¸ÃË÷Òý½Úµã´¢´æ×ÅÎļþµÄÐÅÏ¢£¬ÏñÎļþµÄȨÏÞ£»Í¬Ê±»¹ÓÐÔÚÄĶùÄÜÕÒµ½ÎļþÖеÄÊý¾Ý¡£
ÒòΪÎÒÃÇÎÞ·¨µÃÖª¸ÃÎļþÊDZ»´ò¿ªµÄ»ò¹Ø±ÕµÄ£¬ÎÒÃÇÒ²ÎÞ·¨È¥Ê¹Óúê try_module_getºÍtry_module_putÔÚÏÂÃæµÄÄ£¿éÖУ¬ ÎÒÃÇÎÞ·¨±ÜÃâ¸ÃÎļþ±»´ò¿ª¶øͬʱģ¿éÓÖ±»Ð¶ÔØ¡£ÔÚÏÂÕÂÖÐÎÒ½«½éÉÜÒ»¸ö½ÏÄÑʵÏÖ£¬È´¸üÁé»î£¬¸ü°²È«µÄ´¦Àí /procÎļþµÄ·½·¨¡£
Example 5-1. procfs.c
/*
* procfs.c - create a "file" in /proc
*/
#include
#include
#include
struct proc_dir_entry *Our_Proc_File;
/* Put data into the proc fs file.
*
* Arguments
* =========
* 1. The buffer where the data is to be inserted, if
* you decide to use it.
* 2. A pointer to a pointer to characters. This is
* useful if you don't want to use the buffer
* allocated by the kernel.
* 3. The current position in the file
* 4. The size of the buffer in the first argument.
* 5. Write a "1" here to indicate EOF.
* 6. A pointer to data (useful in case one common
* read for multiple /proc/... entries)
*
* Usage and Return Value
* ======================
* A return value of zero means you have no further
* information at this time (end of file). A negative
* return value is an error condition.
*
* For More Information
* ====================
* The way I discovered what to do with this function
* wasn't by reading documentation, but by reading the
* code which used it. I just looked to see what uses
* the get_info field of proc_dir_entry struct (I used a
* combination of find and grep, if you're interested),
* and I saw that it is used in
*
* If something is unknown about the kernel, this is
* usually the way to go. In Linux we have the great
* advantage of having the kernel source code for
* free - use it.
*/
ssize_t
procfile_read(char *buffer,
char **buffer_location,
off_t offset, int buffer_length, int *eof, void *data)
{
printk(KERN_INFO "inside /proc/test : procfile_read\n" );
int len = 0; /* The number of bytes actually used */
static int count = 1;
/*
* We give all of our information in one go, so if the
* user asks us if we have more information the
* answer should always be no.
*
* This is important because the standard read
* function from the library would continue to issue
* the read system call until the kernel replies
* that it has no more information, or until its
* buffer is filled.
*/
if (offset > 0) {
printk(KERN_INFO "offset %d : /proc/test : procfile_read, \
wrote %d Bytes\n", (int)(offset), len);
*eof = 1;
return len;
}
/*
* Fill the buffer and get its length
*/
len = sprintf(buffer,
"For the %d%s time, go away!\n", count,
(count % 100 > 10 && count % 100 < 14) ? "th" :
(count % 10 == 1) ? "st" :
(count % 10 == 2) ? "nd" :
(count % 10 == 3) ? "rd" : "th" );
count++;
/*
* Return the length
*/
printk(KERN_INFO
"leaving /proc/test : procfile_read, wrote %d Bytes\n", len);
return len;
}
int init_module()
{
int rv = 0;
Our_Proc_File = create_proc_entry("test", 0644, NULL);
Our_Proc_File->read_proc = procfile_read;
Our_Proc_File->owner = THIS_MODULE;
Our_Proc_File->mode = S_IFREG | S_IRUGO;
Our_Proc_File->uid = 0;
Our_Proc_File->gid = 0;
Our_Proc_File->size = 37;
printk(KERN_INFO "Trying to create /proc/test:\n" );
if (Our_Proc_File == NULL) {
rv = -ENOMEM;
remove_proc_entry("test", &proc_root);
printk(KERN_INFO "Error: Could not initialize /proc/test\n" );
} else {
printk(KERN_INFO "Success!\n" );
}
return rv;
}
void cleanup_module()
{
remove_proc_entry("test", &proc_root);
printk(KERN_INFO "/proc/test removed\n" );
}
Notes
[1] ÕâÊÇÔÚ2.0°æ±¾ÖеÄ×ö·¨£¬ ÔÚ°æ±¾2.2ÖУ¬µ±ÎÒÃÇ°ÑinodeÉèΪ0ʱ£¬¾ÍÒѾÕâÑù×Ô¶¯´¦ÀíÁË¡£
febspeolal ÓÚ 2006-11-09 01:09:11·¢±í:
Chapter 4. Character Device Files
/* for put_user */
×Ö·ûÉ豸Îļþ
¹ØÓÚfile_operations½á¹¹Ìå
½á¹¹Ìåfile_operationsÔÚÍ·Îļþ linux/fs.hÖж¨Ò壬ÓÃÀ´´æ´¢Çý¶¯ÄÚºËÄ£¿éÌṩµÄ¶Ô É豸½øÐи÷ÖÖ²Ù×÷µÄº¯ÊýµÄÖ¸Õë¡£¸Ã½á¹¹ÌåµÄÿ¸öÓò¶¼¶ÔÓ¦×ÅÇý¶¯ÄÚºËÄ£¿éÓÃÀ´´¦Àíij¸ö±»ÇëÇóµÄ ÊÂÎñµÄº¯ÊýµÄµØÖ·¡£
¾Ù¸öÀý×Ó£¬Ã¿¸ö×Ö·ûÉ豸ÐèÒª¶¨ÒåÒ»¸öÓÃÀ´¶ÁÈ¡É豸Êý¾ÝµÄº¯Êý¡£½á¹¹Ìå file_operationsÖд洢×ÅÄÚºËÄ£¿éÖÐÖ´ÐÐÕâÏî²Ù×÷µÄº¯ÊýµÄµØÖ·¡£Ò»ÏÂÊǸýṹÌå ÔÚÄÚºË2.6.5Öп´ÆðÀ´µÄÑù×Ó£º
struct file_operations {
struct module *owner;
loff_t(*llseek) (struct file *, loff_t, int);
ssize_t(*read) (struct file *, char __user *, size_t, loff_t *);
ssize_t(*aio_read) (struct kiocb *, char __user *, size_t, loff_t);
ssize_t(*write) (struct file *, const char __user *, size_t, loff_t *);
ssize_t(*aio_write) (struct kiocb *, const char __user *, size_t,
loff_t);
int (*readdir) (struct file *, void *, filldir_t);
unsigned int (*poll) (struct file *, struct poll_table_struct *);
int (*ioctl) (struct inode *, struct file *, unsigned int,
unsigned long);
int (*mmap) (struct file *, struct vm_area_struct *);
int (*open) (struct inode *, struct file *);
int (*flush) (struct file *);
int (*release) (struct inode *, struct file *);
int (*fsync) (struct file *, struct dentry *, int datasync);
int (*aio_fsync) (struct kiocb *, int datasync);
int (*fasync) (int, struct file *, int);
int (*lock) (struct file *, int, struct file_lock *);
ssize_t(*readv) (struct file *, const struct iovec *, unsigned long,
loff_t *);
ssize_t(*writev) (struct file *, const struct iovec *, unsigned long,
loff_t *);
ssize_t(*sendfile) (struct file *, loff_t *, size_t, read_actor_t,
void __user *);
ssize_t(*sendpage) (struct file *, struct page *, int, size_t,
loff_t *, int);
unsigned long (*get_unmapped_area) (struct file *, unsigned long,
unsigned long, unsigned long,
unsigned long);
};
Çý¶¯ÄÚºËÄ£¿éÊDz»ÐèҪʵÏÖÿ¸öº¯ÊýµÄ¡£ÏñÊÓƵ¿¨µÄÇý¶¯¾Í²»ÐèÒª´ÓĿ¼µÄ½á¹¹ ÖжÁÈ¡Êý¾Ý¡£ÄÇô£¬Ïà¶ÔÓ¦µÄfile_operationsÖصÄÏî¾ÍΪ NULL¡£
gcc»¹ÓÐÒ»¸ö·½±ãʹÓÃÕâÖֽṹÌåµÄÀ©Õ¹¡£Äã»áÔÚ½ÏÏÖ´úµÄÇý¶¯ÄÚºËÄ£¿éÖмûµ½¡£ еÄʹÓÃÕâÖֽṹÌåµÄ·½Ê½ÈçÏ£º
struct file_operations fops = {
read: device_read,
write: device_write,
open: device_open,
release: device_release
};
ͬÑùÒ²ÓÐC99Óï·¨µÄʹÓøýṹÌåµÄ·½·¨£¬²¢ÇÒËü±ÈGNUÀ©Õ¹¸üÊÜÍƼö¡£ÎÒʹÓõİ汾Ϊ 2.95ΪÁË·½±ãÄÇЩÏëÒÆÖ²ÄãµÄ´úÂëµÄÈË£¬Äã×îºÃʹÓÃÕâÖÖÓï·¨¡£Ëü½«Ìá¸ß´úÂëµÄ¼æÈÝÐÔ£º
struct file_operations fops = {
.read = device_read,
.write = device_write,
.open = device_open,
.release = device_release
};
ÕâÖÖÓï·¨ºÜÇåÎú£¬ÄãÒ²±ØÐëÇå³þµÄÒâʶµ½Ã»ÓÐÏÔʾÉùÃ÷µÄ½á¹¹Ìå³ÉÔ±¶¼±»gcc³õʼ»¯ÎªNULL¡£
Ö¸Ïò½á¹¹Ìåstruct file_operationsµÄÖ¸Õëͨ³£ÃüÃûΪfops¡£
¹ØÓÚfile½á¹¹Ìå
ÿһ¸öÉ豸Îļþ¶¼´ú±í×ÅÄÚºËÖеÄÒ»¸öfile½á¹¹Ìå¡£¸Ã½á¹¹ÌåÔÚÍ·Îļþlinux/fs.h¶¨Òå¡£×¢Ò⣬file½á¹¹ÌåÊÇÄں˿ռäµÄ½á¹¹Ì壬 ÕâÒâζ×ÅËü²»»áÔÚÓû§³ÌÐòµÄ´úÂëÖгöÏÖ¡£Ëü¾ø¶Ô²»ÊÇÔÚglibcÖж¨ÒåµÄFILE¡£ FILE×Ô¼ºÒ²´Ó²»ÔÚÄں˿ռäµÄº¯ÊýÖгöÏÖ¡£ËüµÄÃû×ÖȷʵͦÈÃÈËÃÔ»óµÄ¡£ Ëü´ú±í×ÅÒ»¸ö³éÏóµÄ´ò¿ªµÄÎļþ£¬µ«²»ÊÇÄÇÖÖÔÚ´ÅÅÌÉÏÓýṹÌå inode±íʾµÄÎļþ¡£
Ö¸Ïò½á¹¹Ìåstruct fileµÄÖ¸Õëͨ³£ÃüÃûΪfilp¡£ ÄãͬÑù¿ÉÒÔ¿´µ½struct file fileµÄ±í´ï·½Ê½£¬µ«²»Òª±»ËüÓÕ»ó¡£
È¥¿´¿´½á¹¹ÌåfileµÄ¶¨Òå¡£´ó²¿·ÖµÄº¯ÊýÈë¿Ú£¬Ïñ½á¹¹Ìå struct dentryûÓб»É豸Çý¶¯Ä£¿éʹÓã¬Äã´ó¿ÉºöÂÔËüÃÇ¡£ÕâÊÇÒòΪÉ豸Çý¶¯Ä£¿é²¢²»×Ô¼ºÖ±½ÓÌî³ä½á¹¹Ìå file£ºËüÃÇÖ»ÊÇʹÓÃÔڱ𴦽¨Á¢µÄ½á¹¹ÌåfileÖеÄÊý¾Ý¡£
×¢²áÒ»¸öÉ豸
ÈçͬÏÈÇ°ÌÖÂ۵ģ¬×Ö·ûÉ豸ͨ³£Í¨¹ýÔÚ·¾¶/dev[1]É豸ÎÄ ¼þ·ÃÎÊ¡£Ö÷É豸ºÅ¸æËßÄãÄÄЩÇý¶¯Ä£¿éÊÇÓÃÀ´²Ù×ÝÄÄЩӲ¼þÉ豸µÄ¡£´ÓÉ豸ºÅÊÇÇý¶¯Ä£ ¿é×Ô¼ºÊ¹ÓÃÀ´Çø±ðËü²Ù×ݵIJ»Í¬É豸£¬µ±´ËÇý¶¯Ä£¿é²Ù×ݲ»Ö»Ò»¸öÉ豸ʱ¡£
½«ÄÚºËÇý¶¯Ä£¿é¼ÓÔØÈëÄÚºËÒâζ×ÅÒªÏòÄÚºË×¢²á×Ô¼º¡£Õâ¸ö¹¤×÷ÊǺÍÇý¶¯Ä£¿é»ñ µÃÖ÷É豸ºÅʱ³õʼ»¯Ò»Í¬½øÐеġ£Äã¿ÉÒÔʹÓÃÍ·Îļþ linux/fs.hÖеĺ¯Êýregister_chrdevÀ´Êµ ÏÖ¡£
int register_chrdev(unsigned int major, const char *name, struct file_operations *fops);
ÆäÖÐunsigned int majorÊÇÄãÉêÇëµÄÖ÷É豸ºÅ£¬ const char *nameÊǽ«ÒªÔÚÎļþ/proc/devices struct file_operations *fopsÊÇÖ¸ÏòÄãµÄÇý¶¯Ä£¿éµÄ file_operations±íµÄÖ¸Õë¡£¸ºµÄ·µ»ØÖµÒâζ×Å×¢²áʧ°Ü¡£ ×¢Òâ×¢²á²¢²»ÐèÒªÌṩ´ÓÉ豸ºÅ¡£Äں˱¾Éí²¢²»ÔÚÒâ´ÓÉ豸ºÅ¡£
ÏÖÔÚµÄÎÊÌâÊÇÄãÈçºÎÉêÇëµ½Ò»¸öûÓб»Ê¹ÓõÄÖ÷É豸ºÅ£¿×î¼òµ¥µÄ·½·¨ÊDz鿴Îļþ Documentation/devices.txt´ÓÖÐÌôÑ¡Ò»¸öûÓб»Ê¹Óõġ£Õâ²»ÊÇ Ò»ÀÍÓÀÒݵķ½·¨ÒòΪÄãÎÞ·¨µÃÖª¸ÃÖ÷É豸ºÅÔÚ½«À´»á±»Õ¼Óá£×îÖյķ½·¨ÊÇÈÃÄÚºËΪÄ㶯 ̬·ÖÅäÒ»¸ö¡£
Èç¹ûÄãÏòº¯Êýregister_chrdev´«µÝΪ0µÄÖ÷É豸ºÅ£¬ÄÇô ·µ»ØµÄ¾ÍÊǶ¯Ì¬·ÖÅäµÄÖ÷É豸ºÅ¡£¸±×÷ÓþÍÊǼÈÈ»ÄãÎÞ·¨µÃÖªÖ÷É豸ºÅ£¬Äã¾ÍÎÞ·¨Ô¤ÏȽ¨ Á¢Ò»¸öÉ豸Îļþ¡£ ÓжàÖÖ½â¾ö·½·¨¡£µÚÒ»ÖÖ·½·¨ÊÇÐÂ×¢²áµÄÇý¶¯Ä£¿é»áÊä³ö×Ô¼ºÐ·ÖÅä µ½µÄÖ÷É豸ºÅ£¬ËùÒÔÎÒÃÇ¿ÉÒÔÊÖ¹¤½¨Á¢ÐèÒªµÄÉ豸Îļþ¡£µÚ¶þÖÖÊÇÀûÓÃÎļþ /proc/devicesÐÂ×¢²áµÄÇý¶¯Ä£¿éµÄÈë¿Ú£¬ÒªÃ´ÊÖ¹¤½¨Á¢É豸Îļþ£¬ Ҫô±àÒ»¸ö½Å±¾È¥×Ô¶¯¶ÁÈ¡¸ÃÎļþ²¢ÇÒÉú³ÉÉ豸Îļþ¡£µÚÈýÖÖÊÇÔÚÎÒÃǵÄÄ£¿éÖУ¬µ±×¢²á ³É¹¦Ê±£¬Ê¹ÓÃmknodͳµ÷Óý¨Á¢É豸Îļþ²¢ÇÒµ÷Óà rm ɾ³ý¸ÃÉ豸 ÎļþÔÚÇý¶¯Ä£¿éµ÷Óú¯Êýcleanup_moduleÇ°¡£
×¢ÏúÒ»¸öÉ豸
¼´Ê¹Ê±rootÒ²²»ÄÜÔÊÐíËæÒâжÔØÄÚºËÄ£¿é¡£µ±Ò»¸ö½ø³ÌÒѾ´ò¿ªÒ»¸öÉ豸ÎļþʱÎÒ ÃÇжÔØÁ˸ÃÉ豸ÎļþʹÓõÄÄÚºËÄ£¿é£¬ÎÒÃÇ´ËʱÔÙ¶Ô¸ÃÎļþµÄ·ÃÎʽ«»áµ¼Ö¶ÔÒÑжÔصÄÄÚ ºËÄ£¿é´úÂëÄÚ´æÇøµÄ·ÃÎÊ¡£ÐÒÔ˵Ļ°ÎÒÃÇ×î¶à»ñµÃÒ»¸öÌÖÑáµÄ´íÎ󾯸档Èç¹û´ËʱÒѾÔÚ ¸ÃÄÚ´æÇø¼ÓÔØÁËÁíÒ»¸öÄ£¿é£¬µ¹Ã¹µÄÄ㽫»áÔÚÄÚºËÖÐÌøתִÐÐÒâÁÏÍâµÄ´úÂë¡£½á¹ûÊÇÎÞ·¨ Ô¤Áϵģ¬¶øÇÒ¶à°ëÊDz»ÄÇôÁîÈËÓä¿ìµÄ¡£
ƽ³££¬µ±Äã²»ÔÊÐíijÏî²Ù×÷ʱ£¬Äã»áµÃµ½¸Ã²Ù×÷·µ»ØµÄ´íÎóÖµ£¨Ò»°ãΪһ¸ºµÄÖµ£©¡£ µ«¶ÔÓÚÎÞ·µ»ØÖµµÄº¯Êýcleanup_moduleÕâÊDz»¿ÉÄܵġ£È»¶ø£¬È´ÓÐ Ò»¸ö¼ÆÊýÆ÷¸ú×Ù×ÅÓжàÉÙ½ø³ÌÕýÔÚʹÓøÃÄ£¿é¡£Äã¿ÉÒÔͨ¹ý²é¿´Îļþ /proc/modulesµÄµÚÈýÁÐÀ´»ñÈ¡ÕâЩÐÅÏ¢¡£Èç¹û¸ÃÖµ·ÇÁ㣬ÔòжÔØ ¾Í»áʧ°Ü¡£Äã²»ÐèÒªÔÚÄãÄ£¿éÖеĺ¯Êýcleanup_moduleÖмì²é¸Ã ¼ÆÊýÆ÷£¬ÒòΪ¸ÃÏî¼ì²éÓÉÍ·Îļþlinux/module.cÖж¨ÒåµÄϵͳµ÷Óà sys_delete_moduleÍê³É¡£ÄãÒ²²»Ó¦¸ÃÖ±½Ó¶Ô¸Ã¼ÆÊýÆ÷½øÐвÙ×÷¡£ ÄãÓ¦¸ÃʹÓÃÔÚÎļþlinux/modules.h¶¨ÒåµÄºê À´Ôö¼Ó£¬¼õСºÍ¶ÁÈ¡¸Ã¼ÆÊýÆ÷£º
try_module_get(THIS_MODULE): Increment the use count.
try_module_put(THIS_MODULE): Decrement the use count.
±£³Ö¸Ã¼ÆÊýÆ÷ʱ¿Ì¾«È·ÊǷdz£ÖØÒªµÄ£»Èç¹ûÄ㶪ʧÁËÕýÈ·µÄ¼ÆÊý£¬Ä㽫ÎÞ·¨Ð¶ÔØÄ£¿é£¬ ÄǾÍÖ»ÓÐÖØÆôÁË¡£²»¹ýÕâÖÖÇé¿öÔÚ½ñºó±àдÄÚºËÄ£¿éʱҲÊÇÎÞ·¨±ÜÃâµÄ¡£
chardev.c
ÏÂÃæµÄ´úÂëʾ·¶ÁËÒ»¸ö½Ð×öchardevµÄ×Ö·ûÉ豸¡£Äã¿ÉÒÔÓà catÊä³ö¸ÃÉ豸ÎļþµÄÄÚÈÝ£¨»òÓñðµÄ³ÌÐò´ò¿ªËü£©Ê±£¬Çý¶¯Ä£¿é »á½«¸ÃÉ豸Îļþ±»¶ÁÈ¡µÄ´ÎÊýÏÔʾ¡£Ä¿Ç°¶ÔÉ豸ÎļþµÄд²Ù×÷»¹²»±»Ö§³Ö£¨Ïñecho "hi" > /dev/hello£©£¬µ«»á²¶×½ÕâЩ²Ù×÷²¢ÇÒ¸æËßÓû§¸Ã²Ù×÷²»±»Ö§³Ö¡£²»Òªµ£ÐÄÎÒ ÃǶԶÁÈ뻺³åÇøµÄÊý¾Ý×öÁËʲô£»ÎÒÃÇʲô¶¼Ã»×ö¡£ÎÒÃÇÖ»ÊǶÁÈëÊý¾Ý²¢Êä³öÎÒÃÇÒѾ½Ó ÊÕµ½µÄÊý¾ÝµÄÐÅÏ¢¡£
Example 4-1. chardev.c
/*
* chardev.c: Creates a read-only char device that says how many times
* you've read from the dev file
*/
#include
#include
#include
#include
/*
* Prototypes - this would normally go in a .h file
*/
int init_module(void);
void cleanup_module(void);
static int device_open(struct inode *, struct file *);
static int device_release(struct inode *, struct file *);
static ssize_t device_read(struct file *, char *, size_t, loff_t *);
static ssize_t device_write(struct file *, const char *, size_t, loff_t *);
#define SUCCESS 0
#define DEVICE_NAME "chardev" /* Dev name as it appears in /proc/devices */
#define BUF_LEN 80 /* Max length of the message from the device */
/*
* Global variables are declared as static, so are global within the file.
*/
static int Major; /* Major number assigned to our device driver */
static int Device_Open = 0; /* Is device open?
* Used to prevent multiple access to device */
static char msg[BUF_LEN]; /* The msg the device will give when asked */
static char *msg_Ptr;
static struct file_operations fops = {
.read = device_read,
.write = device_write,
.open = device_open,
.release = device_release
};
/*
* Functions
*/
int init_module(void)
{
Major = register_chrdev(0, DEVICE_NAME, &fops);
if (Major < 0) {
printk("Registering the character device failed with %d\n",
Major);
return Major;
}
printk("<1>I was assigned major number %d. To talk to\n", Major);
printk("<1>the driver, create a dev file with\n");
printk("'mknod /dev/hello c %d 0'.\n", Major);
printk("<1>Try various minor numbers. Try to cat and echo to\n");
printk("the device file.\n");
printk("<1>Remove the device file and module when done.\n");
return 0;
}
void cleanup_module(void)
{
/*
* Unregister the device
*/
int ret = unregister_chrdev(Major, DEVICE_NAME);
if (ret < 0)
printk("Error in unregister_chrdev: %d\n", ret);
}
/*
* Methods
*/
/*
* Called when a process tries to open the device file, like
* "cat /dev/mycharfile"
*/
static int device_open(struct inode *inode, struct file *file)
{
static int counter = 0;
if (Device_Open)
return -EBUSY;
Device_Open++;
sprintf(msg, "I already told you %d times Hello world!\n", counter++);
msg_Ptr = msg;
try_module_get(THIS_MODULE);
return SUCCESS;
}
/*
* Called when a process closes the device file.
*/
static int device_release(struct inode *inode, struct file *file)
{
Device_Open--; /* We're now ready for our next caller */
/*
* Decrement the usage count, or else once you opened the file, you'll
* never get get rid of the module.
*/
module_put(THIS_MODULE);
return 0;
}
/*
* Called when a process, which already opened the dev file, attempts to
* read from it.
*/
static ssize_t device_read(struct file *filp, /* see include/linux/fs.h */
char *buffer, /* buffer to fill with data */
size_t length, /* length of the buffer */
loff_t * offset)
{
/*
* Number of bytes actually written to the buffer
*/
int bytes_read = 0;
/*
* If we're at the end of the message,
* return 0 signifying end of file
*/
if (*msg_Ptr == 0)
return 0;
/*
* Actually put the data into the buffer
*/
while (length && *msg_Ptr) {
/*
* The buffer is in the user data segment, not the kernel
* segment so "*" assignment won't work. We have to use
* put_user which copies data from the kernel data segment to
* the user data segment.
*/
put_user(*(msg_Ptr++), buffer++);
length--;
bytes_read++;
}
/*
* Most read functions return the number of bytes put into the buffer
*/
return bytes_read;
}
/*
* Called when a process writes to dev file: echo "hi" > /dev/hello
*/
static ssize_t
device_write(struct file *filp, const char *buff, size_t len, loff_t * off)
{
printk("<1>Sorry, this operation isn't supported.\n");
return -EINVAL;
}
Ϊ¶à¸ö°æ±¾µÄÄں˱àдÄÚºËÄ£¿é
ϵͳµ÷Óã¬Ò²¾ÍÊÇÄÚºËÌṩ¸ø½ø³ÌµÄ½Ó¿Ú£¬»ù±¾ÉÏÊDZ£³Ö²»±äµÄ¡£Ò²Ðí»áÌíÈëÐÂµÄ ÏµÍ³µ÷Ó㬵«ÄÇЩÒÑÓеIJ»»á±»¸Ä¶¯¡£Õâ¶ÔÓÚÏòϼæÈÝÊǷdz£ÖØÒªµÄ¡£ÔÚ¶àÊýÇé¿öÏ£¬Éè ±¸ÎļþÊDZ£³Ö²»±äµÄ¡£µ«Äں˵ÄÄÚ²¿ÔÚ²»Í¬°æ±¾Ö®¼ä»¹ÊÇ»áÓÐÇø±ðµÄ¡£
LinuxÄں˷ÖΪÎȶ¨°æ±¾£¨°æ±¾ºÅÖмäΪżÊý£©ºÍÊÔÑé°æ±¾£¨°æ±¾ºÅÖмäΪÆæÊý£©¡£ ÊÔÑé°æ±¾ÖпÉÒÔÊÔÑé¸÷ÖÖ¸÷ÑùµÄжø¿áµÄÖ÷Ò⣬ÓÐЩ»á±»Ö¤ÊµÊÇÒ»¸ö´íÎó£¬ÓÐЩÔÚÏÂÒ»°æ ÖлᱻÍêÉÆ¡£×ÜÖ®£¬Äã²»ÄÜÒÀÀµÕâЩ°æ±¾ÖеĽӿڣ¨ÕâÒ²ÊÇÎÒ²»ÔÚ±¾ÎĵµÖÐÖ§³ÖËüÃǵÄÔÒò£¬ ËüÃǸüеÄÌ«¿ìÁË)¡£ÔÚÎȶ¨°æ±¾ÖУ¬ÎÒÃÇ¿ÉÒÔÆÚÍû½Ó¿Ú±£³ÖÒ»Ö£¬³ýÁËÄÇЩÐ޸ĴúÂëÖдíÎóµÄ°æ±¾¡£
Èç¹ûÄãÒªÖ§³Ö¶à°æ±¾µÄÄںˣ¬ÄãÐèÒª±àдΪ²»Í¬Äں˱àÒëµÄ´úÂëÊ÷¡£¿ÉÒÔͨ¹ý±È½Ïºê LINUX_VERSION_CODEºÍºêKERNEL_VERSIONÔÚ°æ±¾ºÅΪa.b.c µÄÄÚºËÖУ¬¸ÃºêµÄÖµÓ¦¸ÃΪ 2^16¡Áa+2^8¡Áb+c
ÔÚÉÏÒ»¸ö°æ±¾ÖиÃÎĵµ»¹±£ÁôÁËÏêϸµÄÈçºÎÏòºó¼æÈÝÀÏÄں˵ĽéÉÜ£¬ÏÖÔÚÎÒÃǾö¶¨´òÆÆÕâ¸ö´«Í³¡£ ¶ÔΪÀÏÄں˱àдÇý¶¯¸ÐÐËȤµÄ¶ÁÕßÓ¦¸Ã²Î¿¼¶ÔÓ¦°æ±¾µÄLKMPG£¬Ò²¾ÍÊÇ˵£¬2.4.x°æ±¾µÄLKMPG¶ÔÓ¦ 2.4.xµÄÄںˣ¬2.6.x°æ±¾µÄLKMPG¶ÔÓ¦2.6.xµÄÄںˡ£
Notes
[1] ÕâÖ»ÊÇÏ°¹ßÉϵġ£½«É豸Îļþ·Å ÔÚÄãµÄÓû§Ä¿Â¼ÏÂÊÇûÓÐÎÊÌâµÄ¡£µ«Êǵ±ÕæÕýÌṩ³ÉÊìµÄÇý¶¯Ä£¿éʱ£¬Çë±£Ö¤½«É豸ÎÄ ¼þ·ÅÔÚ/devÏ¡£
febspeolal ÓÚ 2006-11-09 01:08:47·¢±í:
Chapter 3. Preliminaries
ÄÚºËÄ£¿éºÍÓû§³ÌÐòµÄ±È½Ï
ÄÚºËÄ£¿éÊÇÈçºÎ¿ªÊ¼ºÍ½áÊøµÄ
Óû§³ÌÐòͨ³£´Óº¯Êýmain()¿ªÊ¼£¬Ö´ÐÐһϵÁеÄÖ¸Áî²¢ÇÒ µ±Ö¸ÁîÖ´ÐÐÍê³Éºó½áÊø³ÌÐò¡£ÄÚºËÄ£¿éÓÐÒ»µã²»Í¬¡£ÄÚºËÄ£¿éҪô´Óº¯Êýinit_module »òÊÇÄãÓúêmodule_initÖ¸¶¨µÄº¯Êýµ÷ÓÿªÊ¼¡£Õâ¾ÍÊÇÄÚºËÄ£¿é µÄÈë¿Úº¯Êý¡£Ëü¸æËßÄÚºËÄ£¿éÌṩÄÇЩ¹¦ÄÜÀ©Õ¹²¢ÇÒÈÃÄÚºË×¼±¸ºÃÔÚÐèҪʱµ÷ÓÃËü¡£ µ±ËüÍê³ÉÕâЩºó£¬¸Ãº¯Êý¾ÍÖ´ÐнáÊøÁË¡£Ä£¿éÔÚ±»Äں˵÷ÓÃǰҲʲô¶¼²»×ö¡£
ËùÓеÄÄ£¿é»òÊǵ÷ÓÃcleanup_module»òÊÇÄãÓúê module_exitÖ¸¶¨µÄº¯Êý¡£ÕâÊÇÄ£¿éµÄÍ˳öº¯Êý¡£Ëü³·ÏûÈë¿Úº¯ÊýËù×öµÄÒ»ÇС£ ÀýÈç×¢ÏúÈë¿Úº¯ÊýËù×¢²áµÄ¹¦ÄÜ¡£
ËùÓеÄÄ£¿é¶¼±ØÐëÓÐÈë¿Úº¯ÊýºÍÍ˳öº¯Êý¡£¼ÈÈ»ÎÒÃÇÓв»Ö»Ò»ÖÖ·½·¨È¥¶¨ÒåÕâÁ½¸ö º¯Êý£¬ÎÒ½«Å¬Á¦Ê¹Óá°Èë¿Úº¯Êý¡±ºÍ¡°Í˳öº¯Êý¡±À´ÃèÊö ËüÃÇ¡£µ«Êǵ±ÎÒÖ»ÓÃinit_module ºÍcleanup_moduleʱ£¬ÎÒÏ£ÍûÄãÃ÷°×ÎÒÖ¸µÄÊÇʲô¡£
Ä£¿é¿Éµ÷Óõĺ¯Êý
³ÌÐòÔ±²¢²»×ÜÊÇ×Ô¼ºÐ´ËùÓÐÓõ½µÄº¯Êý¡£Ò»¸ö³£¼ûµÄ»ù±¾µÄÀý×Ó¾ÍÊÇ printf()ÄãʹÓÃÕâЩC±ê×¼¿â£¬libcÌṩµÄ¿âº¯Êý¡£ ÕâЩº¯Êý(Ïñprintf()) ʵ¼ÊÉÏÔÚÁ¬½Ó֮ǰ²¢²»½øÈëÄãµÄ³ÌÐò¡£ ÔÚÁ¬½ÓʱÕâЩº¯Êýµ÷ÓòŻáÖ¸Ïò Äãµ÷ÓõĿ⣬´Ó¶øʹÄãµÄ´úÂë×îÖÕ¿ÉÒÔÖ´ÐС£
ÄÚºËÄ£¿éÓÐËù²»Í¬¡£ÔÚhello worldÄ£¿éÖÐÄãÒ²ÐíÒѾעÒâµ½ÁËÎÒÃÇʹÓõĺ¯Êý printk() ȴûÓаüº¬±ê×¼I/O¿â¡£ÕâÊÇÒòΪģ¿éÊÇÔÚinsmod¼Ó ÔØʱ²ÅÁ¬½ÓµÄÄ¿±êÎļþ¡£ÄÇЩҪÓõ½µÄº¯ÊýµÄ·ûºÅÁ´½ÓÊÇÄÚºË×Ô¼ºÌṩµÄ¡£ Ò²¾ÍÊÇ˵£¬ Äã¿ÉÒÔÔÚÄÚºËÄ£¿éÖÐʹÓõĺ¯ÊýÖ»ÄÜÀ´×ÔÄں˱¾Éí¡£Èç¹ûÄã¶ÔÄÚºËÌṩÁËÄÄЩº¯Êý·ûºÅ Á´½Ó¸ÐÐËȤ£¬¿´Ò»¿´Îļþ/proc/kallsyms¡£
ÐèҪעÒâµÄÒ»µãÊǿ⺯ÊýºÍϵͳµ÷ÓõÄÇø±ð¡£¿âº¯ÊýÊǸ߲ãµÄ£¬ÍêÈ«ÔËÐÐÔÚÓû§¿Õ¼ä£¬ Ϊ³ÌÐòÔ±Ìṩµ÷ÓÃÕæÕýµÄÔÚÄ»ºó Íê³Éʵ¼ÊÊÂÎñµÄϵͳµ÷Óõĸü·½±ãµÄ½Ó¿Ú¡£ÏµÍ³µ÷ÓÃÔÚÄÚºË Ì¬ÔËÐв¢ÇÒÓÉÄÚºË×Ô¼ºÌṩ¡£±ê×¼C¿âº¯Êýprintf()¿ÉÒÔ±»¿´×öÊÇÒ» ¸öͨÓõÄÊä³öÓï¾ä£¬µ«Ëüʵ¼Ê×öµÄÊǽ«Êý¾Ýת»¯Îª·ûºÏ¸ñʽµÄ×Ö·û´®²¢ÇÒµ÷ÓÃϵͳµ÷Óà write()Êä³öÕâЩ×Ö·û´®¡£
ÊÇ·ñÏë¿´Ò»¿´printf()¾¿¾¹Ê¹ÓÃÁËÄÄЩϵͳµ÷ÓÃ? ÕâºÜÈÝÒ×£¬±àÒëÏÂÃæµÄ´úÂë¡£
#include
int main(void)
{ printf("hello" ); return 0; }
ʹÓÃÃüÁîgcc -Wall -o hello hello.c±àÒë¡£ÓÃÃüÁî strace helloÐиÿÉÖ´ÐÐÎļþ¡£ÊÇ·ñºÜ¾ªÑÈ£¿ ÿһÐж¼ºÍÒ»¸öϵͳµ÷ÓÃÏà¶ÔÓ¦¡£ strace[1] ÊÇÒ»¸ö·Ç³£ÓÐÓõijÌÐò£¬Ëü¿ÉÒÔ¸æËßÄã³ÌÐòʹÓÃÁËÄÄЩϵͳµ÷ÓúÍÕâЩϵͳµ÷ÓõIJÎÊý£¬·µ»ØÖµ¡£ ÕâÊÇÒ»¸ö¼«ÓмÛÖµµÄ²é¿´³ÌÐòÔÚ¸ÉʲôµÄ¹¤¾ß¡£ÔÚÊä³öµÄĩ⣬ÄãÓ¦¸Ã¿´µ½ÕâÑùÀàËƵÄÒ»ÐÐ write(1, "hello", 5hello)¡£Õâ¾ÍÊÇÎÒÃÇÒªÕҵġ£²ØÔÚÃæ¾ßprintf() µÄÕæʵÃæÄ¿¡£¼ÈÈ»¾ø´ó¶àÊýÈËʹÓÿ⺯ÊýÀ´¶ÔÎļþI/O½øÐвÙ×÷(Ïñ fopen, fputs, fclose)¡£ Äã¿ÉÒԲ鿴man˵Ã÷µÄµÚ¶þ²¿·ÖʹÓÃÃüÁîman 2 write. ¡£man˵Ã÷µÄµÚ¶þ²¿·Ö רÃŽéÉÜϵͳµ÷ÓÃ(Ïñkill()ºÍread())¡£ man˵Ã÷µÄµÚÈý²¿·ÖÔòרÃŽéÉÜÄã¿ÉÄܸüÊìϤµÄ¿âº¯Êý£¬ (Ïñcosh()ºÍrandom())¡£
ÄãÉõÖÁ¿ÉÒÔ±àд´úÂëÈ¥¸²¸Çϵͳµ÷Óã¬ÕýÈçÎÒÃDz»¾ÃÒª×öµÄ¡£º§¿Í³£ÕâÑù×öÀ´ÎªÏµÍ³°²×°ºóÃÅ»òľÂí¡£ µ«Äã¿ÉÒÔÓÃËüÀ´Íê³ÉһЩ¸üÓÐÒæµÄÊ£¬ÏñÈÃÄÚºËÔÚÿ´ÎijÈËɾ³ýÎļþʱÊä³ö ¡° Tee hee, that tickles!¡± µÄÐÅÏ¢¡£
Óû§¿Õ¼äºÍÄں˿ռä
ÄÚºËȫȨ¸ºÔð¶ÔÓ²¼þ×ÊÔ´µÄ·ÃÎÊ£¬²»¹Ü±»·ÃÎʵÄÊÇÏÔʾ¿¨£¬Ó²ÅÌ£¬»¹ÊÇÄÚ´æ¡£ Óû§³ÌÐò³£ÎªÕâЩ×ÊÔ´¾ºÕù¡£¾ÍÈçͬÎÒÔÚ±£´æÕâ ·ÝÎĵµÍ¬Ê±±¾µØÊý¾Ý¿âÕýÔÚ¸üС£ Îҵıà¼Æ÷vim½ø³ÌºÍÊý¾Ý¿â¸üнø³ÌͬʱҪÇó·ÃÎÊÓ²ÅÌ¡£Äں˱ØÐëʹÕâЩÇëÇóÓÐÌõ²»ÎɵĽøÐУ¬ ¶ø²»ÊÇËæÓû§µÄÒâÔ¸Ìṩ¼ÆËã»ú×ÊÔ´¡£ Ϊ·½±ãʵÏÖÕâÖÖ»úÖÆ£¬ CPU ¿ÉÒÔÔÚ²»Í¬µÄ״̬ÔËÐС£²»Í¬µÄ״̬¸³Ó費ͬµÄÄã¶Ôϵͳ²Ù×÷µÄ×ÔÓÉ¡£Intel 80836 ¼Ü¹¹ÓÐËÄÖÖ״̬¡£ UnixֻʹÓÃÁËÆäÖÐ µÄÁ½ÖÖ£¬×î¸ß¼¶µÄ״̬(²Ù×÷״̬0,¼´¡°³¬¼¶×´Ì¬¡±£¬¿ÉÒÔÖ´ÐÐÈκβÙ×÷)ºÍ×îµÍ¼¶µÄ״̬ (¼´¡°Óû§×´Ì¬¡±)¡£
»ØÒäÒÔÏÂÎÒÃǶԿ⺯ÊýºÍϵͳµ÷ÓõÄÌÖÂÛ£¬Ò»°ã¿âº¯ÊýÔÚÓû§Ì¬Ö´ÐС£ ¿âº¯Êýµ÷ÓÃÒ»¸ö»ò¼¸¸öϵͳµ÷Ó㬶øÕâЩϵͳµ÷ÓÃΪ¿âº¯ÊýÍê³É¹¤×÷£¬µ«ÊÇÔÚ³¬¼¶×´Ì¬¡£ Ò»µ©ÏµÍ³µ÷ÓÃÍê³É¹¤×÷ºóϵͳµ÷Óþͷµ»Øͬʱ³ÌÐòÒ²·µ»ØÓû§Ì¬¡£
ÃüÃû¿Õ¼ä
Èç¹ûÄãÖ»ÊÇдһЩ¶ÌСµÄC³ÌÐò£¬Äã¿ÉΪÄãµÄ±äÁ¿ÆðÒ»¸ö·½±ãµÄºÍÒ×ÓÚÀí½âµÄ±äÁ¿Ãû¡£ µ«ÊÇ£¬Èç¹ûÄãдµÄ´úÂëÖ»ÊÇ Ðí¶àÆäËüÈËдµÄ´úÂëµÄÒ»²¿·Ö£¬ÄãµÄÈ«¾ÖһЩ¾Í»áÓëÆäÖеÄÈ«¾Ö±äÁ¿·¢Éú³åÍ»¡£ ÁíÒ»¸öÇé¿öÊÇÒ»¸ö³ÌÐòÖÐÓÐÌ«¶àµÄ ÄÑÒÔÀí½âµÄ±äÁ¿Ãû£¬ÕâÓֻᵼÖ±äÁ¿ÃüÃû¿Õ¼äÎÛȾ ÔÚ´óÐÍÏîÄ¿ÖУ¬±ØÐëŬÁ¦¼Çס±£ÁôµÄ±äÁ¿Ãû£¬»òΪ¶ÀÒ»ÎÞ¶þµÄÃüÃûʹÓÃÒ»ÖÖͳһµÄ·½·¨¡£
µ±±àдÄں˴úÂëʱ£¬¼´Ê¹ÊÇ×îСµÄÄ£¿éÒ²»áͬÕû¸öÄÚºËÁ¬½Ó£¬ËùÒÔÕâµÄÈ·ÊǸöÁîÈËÍ·Í´µÄÎÊÌâ¡£ ×îºÃµÄ½â¾ö·½·¨ÊÇÉùÃ÷ÄãµÄ±äÁ¿Îªstatic¾²Ì¬µÄ²¢ÇÒΪÄãµÄ·ûºÅʹÓÃÒ»¸ö¶¨ÒåµÄºÜºÃµÄǰ׺¡£ ´«Í³ÖУ¬Ê¹ÓÃСд×ÖĸµÄÄÚºËǰ׺¡£Èç¹ûÄã²»Ï뽫ËùÓеĶ«Î÷¶¼ÉùÃ÷Ϊstatic¾²Ì¬µÄ£¬ ÁíÒ»¸öÑ¡ÔñÊÇÉùÃ÷Ò»¸ösymbol table£¨·ûºÅ±í£©²¢ÏòÄÚºË×¢²á¡£ÎÒÃǽ«ÔÚÒÔºóÌÖÂÛ¡£
Îļþ/proc/kallsyms±£´æ×ÅÄÚºËÖªµÀµÄËùÓеķûºÅ£¬Äã¿ÉÒÔ·ÃÎÊËüÃÇ£¬ ÒòΪËüÃÇÊÇÄں˴úÂë¿Õ¼äµÄÒ»²¿·Ö¡£
´úÂë¿Õ¼ä
ÄÚ´æ¹ÜÀíÊÇÒ»¸ö·Ç³£¸´ÔӵĿÎÌâ¡£O'ReillyµÄ¡¶Understanding The Linux Kernel¡·¾ø´ó²¿·Ö¶¼ÔÚ ÌÖÂÛÄÚ´æ¹ÜÀí£¡ÎÒÃÇ ²¢²»×¼±¸×¨×¢ÓÚÄÚ´æ¹ÜÀí£¬µ«ÓÐһЩ¶«Î÷»¹ÊǵÃÖªµÀµÄ¡£
Èç¹ûÄãûÓÐÈÏÕ濼ÂǹýÄÚ´æÉè¼ÆȱÏÝÒâζ×Åʲô£¬ÄãÒ²Ðí»á¾ªÑȵĻñÖªÒ»¸öÖ¸Õë²¢²»Ö¸ÏòÒ»¸öÈ·ÇÐ µÄÄÚ´æÇøÓò¡£µ±Ò»¸ö½ø³Ì½¨Á¢Ê±£¬ÄÚºËΪËü·ÖÅäÒ»²¿·ÖÈ·ÇеÄʵ¼ÊÄÚ´æ¿Õ¼ä²¢°ÑËü½»¸ø½ø³Ì£¬±»½ø³ÌµÄ ´úÂ룬±äÁ¿£¬¶ÑÕ»ºÍÆäËüһЩ¼ÆËã»úѧµÄר¼Ò²ÅÃ÷°×µÄ¶«Î÷ʹÓÃ[2]¡£ÕâЩÄÚ´æ´Ó$0$ ¿ªÊ¼²¢¿ÉÒÔÀ©Õ¹µ½ÐèÒªµÄµØ·½¡£ÕâЩ ÄÚ´æ¿Õ¼ä²¢²»Öصþ£¬ËùÒÔ¼´Ê¹½ø³Ì·ÃÎÊͬһ¸öÄÚ´æµØÖ·£¬ÀýÈç0xbffff978£¬ ÕæʵµÄÎïÀíÄÚ´æµØÖ·ÆäʵÊDz»Í¬µÄ¡£½ø³Ìʵ¼ÊÖ¸ÏòµÄÊÇÒ»¿é±»·ÖÅäµÄÄÚ´æÖÐÒÔ0xbffff978 ΪƫÒÆÁ¿µÄÒ»¿éÄÚ´æÇøÓò¡£¾ø´ó¶àÊýÇé¿öÏ£¬Ò»¸ö½ø³ÌÏñÆÕͨµÄ"Hello, World"²»¿ÉÒÔ·ÃÎʱðµÄ½ø³ÌµÄ ÄÚ´æ¿Õ¼ä£¬¾¡¹ÜÓÐʵÏÖÕâÖÖ»úÖƵķ½·¨¡£ ÎÒÃǽ«ÔÚÒÔºóÌÖÂÛ¡£
ÄÚºË×Ô¼ºÒ²ÓÐÄÚ´æ¿Õ¼ä¡£¼ÈȻһ¸öÄÚºËÄ£¿é¿ÉÒÔ¶¯Ì¬µÄ´ÓÄÚºËÖмÓÔغÍжÔØ£¬ËüÆäʵÊǹ²ÏíÄÚºËµÄ ÄÚ´æ¿Õ¼ä¶ø²»ÊÇ×Ô¼ºÓµÓÐ ¶ÀÁ¢µÄÄÚ´æ¿Õ¼ä¡£Òò´Ë£¬Ò»µ©ÄãµÄÄ£¿é¾ßÓÐÄÚ´æÉè¼ÆȱÏÝ£¬Äں˾ÍÊÇÄÚ´æÉè¼ÆȱÏÝÁË¡£ Èç¹ûÄãÔÚ´íÎóµÄ¸²¸ÇÊý¾Ý£¬ÄÇôÄã¾ÍÔÚ ÆÆ»µÄں˵ĴúÂë¡£Õâ±ÈÏÖÔÚÌýÆðÀ´µÄ»¹Ôã¡£ËùÒÔ¾¡Á¿Ð¡ÐĽ÷É÷¡£
˳±ãÌáһϣ¬ÒÔÉÏÎÒËùÖ¸³öµÄ¶ÔÓÚÈκε¥ÕûÌåÄں˵IJÙ×÷ϵͳ¶¼ÊÇÕæʵµÄ[3]¡£ Ò²´æÔÚÄ£¿é»¯Î¢Äں˵IJÙ×÷ϵͳ£¬Èç GNU Hurd ºÍ QNX Neutrino¡£
Device Drivers
Ò»ÖÖÄÚºËÄ£¿éÊÇÉ豸Çý¶¯³ÌÐò£¬ÎªÊ¹ÓÃÓ²¼þÉ豸ÏñµçÊÓ¿¨ºÍ´®¿Ú¶ø±àд¡£ ÔÚUnixÖУ¬ÈκÎÉ豸¶¼±»µ±×÷·¾¶/dev µÄÉ豸Îļþ´¦Àí£¬²¢Í¨¹ýÕâЩÉ豸ÎļþÌṩ·ÃÎÊÓ²¼þµÄ·½·¨¡£ É豸Çý¶¯ÎªÓû§³ÌÐò ·ÃÎÊÓ²¼þÉ豸¡£¾ÙÀýÀ´Ëµ£¬Éù¿¨É豸Çý¶¯³ÌÐòes1370.o½«»á°ÑÉ豸Îļþ /dev/soundͬÉù¿¨Ó²¼þEnsoniq IS1370ÁªÏµÆðÀ´¡£ ÕâÑùÓû§³ÌÐòÏñ mp3blaster ¾Í¿ÉÒÔͨ¹ý·ÃÎÊÉ豸Îļþ/dev/sound ÔËÐжø²»±ØÖªµÀÄÇÖÖÉù¿¨Ó²¼þ°²×°ÔÚϵͳÉÏ¡£
Major and Minor Numbers
ÈÃÎÒÃÇÀ´Ñо¿¼¸¸öÉ豸Îļþ¡£ÕâÀïµÄ¼¸¸öÉ豸Îļþ´ú±í×ÅÒ»¿éÖ÷IDEÓ²ÅÌÉϵÄÍ·Èý¸ö·ÖÇø£º
# ls -l /dev/hda[1-3]
brw-rw---- 1 root disk 3, 1 Jul 5 2000 /dev/hda1
brw-rw---- 1 root disk 3, 2 Jul 5 2000 /dev/hda2
brw-rw---- 1 root disk 3, 3 Jul 5 2000 /dev/hda3
×¢Òâһϱ»¶ººÅ¸ô¿ªµÄÁ½ÁС£µÚÒ»¸öÊý×Ö±»½Ð×öÖ÷É豸ºÅ£¬µÚ¶þ¸ö±»½Ð×ö´ÓÉ豸ºÅ¡£ Ö÷É豸ºÅ¾ö¶¨Ê¹ÓúÎÖÖÉ豸Çý¶¯³ÌÐò¡£ ÿÖÖ²»Í¬µÄÉ豸¶¼±»·ÖÅäÁ˲»Í¬µÄÖ÷É豸ºÅ£» ËùÓоßÓÐÏàͬÖ÷É豸ºÅµÄÉ豸Îļþ¶¼ÊDZ»Í¬Ò»¸öÇý¶¯³ÌÐò¿ØÖÆ¡£ÉÏÃæÀý×ÓÖÐµÄ Ö÷É豸ºÅ¶¼Îª3£¬ ±íʾËüÃǶ¼±»Í¬Ò»¸öÇý¶¯³ÌÐò¿ØÖÆ¡£
´ÓÉ豸ºÅÓÃÀ´Çø±ðÇý¶¯³ÌÐò¿ØÖƵĶà¸öÉ豸¡£ÉÏÃæÀý×ÓÖеĴÓÉ豸ºÅ²»ÏàͬÊÇÒòΪËüÃDZ»Ê¶±ðΪ¼¸¸öÉ豸¡£
É豸±»´ó¸ÅµÄ·ÖΪÁ½Àࣺ×Ö·ûÉ豸ºÍ¿éÉ豸¡£Çø±ðÊÇ¿éÉ豸Óлº³åÇø£¬ËùÒÔËüÃÇ¿ÉÒÔ¶ÔÇëÇó½øÐÐÓÅ»¯ÅÅÐò¡£ Õâ¶Ô´æ´¢É豸ÓÈÆä ÖØÒª£¬ÒòΪ¶ÁдÏàÁÚµÄÎļþ×ܱȶÁдÏà¸ôºÜÔ¶µÄÎļþÒª¿ì¡£ÁíÒ»¸öÇø±ðÊÇ¿éÉ豸ÊäÈëºÍÊä³ö ¶¼ÊÇÒÔÊý¾Ý¿éΪµ¥Î»µÄ£¬µ«ÊÇ×Ö·ûÉ豸 ¾Í¿ÉÒÔ×ÔÓɶÁдÈÎÒâÁ¿µÄ×Ö½Ú¡£´ó²¿·ÖÓ²¼þÉ豸Ϊ×Ö·ûÉ豸£¬ÒòΪËüÃÇ ²»ÐèÒª»º³åÇøºÍÊý¾Ý²»ÊÇ°´¿éÀ´´«ÊäµÄ¡£Äã¿ÉÒÔͨ¹ýÃüÁîls -lÊä³öµÄÍ·Ò»¸ö×Öĸʶ±ðÒ»¸ö É豸ΪºÎÖÖÉ豸¡£Èç¹ûÊÇ'b' ¾ÍÊÇ¿éÉ豸£¬Èç¹ûÊÇ'c'¾ÍÊÇ×Ö·ûÉ豸¡£ÒÔÉÏÄã¿´µ½µÄÊÇ¿éÉ豸¡£Õâ¶ù»¹ÓÐһЩ ×Ö·ûÉ豸Îļþ£¨´®¿Ú£©£º
crw-rw---- 1 root dial 4, 64 Feb 18 23:34 /dev/ttyS0
crw-r----- 1 root dial 4, 65 Nov 17 10:26 /dev/ttyS1
crw-rw---- 1 root dial 4, 66 Jul 5 2000 /dev/ttyS2
crw-rw---- 1 root dial 4, 67 Jul 5 2000 /dev/ttyS3
Èç¹ûÄãÏë¿´Ò»ÏÂÒÑ·ÖÅäµÄÖ÷É豸ºÅ¶¼ÊÇЩʲôÉ豸¿ÉÒÔ¿´Ò»ÏÂÎļþ /usr/src/linux/Documentation/devices.txt¡£
ϵͳ°²×°Ê±£¬ËùÓеÄÕâЩÉ豸Îļþ¶¼ÊÇÓÉÃüÁîmknod½¨Á¢µÄ¡£È¥½¨Á¢Ò»¸öеÄÃû½Ð coffee'£¬Ö÷É豸ºÅΪ12ºÍ´ÓÉ豸ºÅΪ2µÄÉ豸Îļþ£¬Ö»Òª¼òµ¥µÄ Ö´ÐÐÃüÁîmknod /dev/coffee c 12 2¡£Äã²¢²»ÊDZØÐ뽫É豸Îļþ·ÅÔÚĿ¼ /devÖУ¬ÕâÖ»ÊÇÒ»¸ö´«Í³¡£Linus±¾ÈËÊÇÕâÑù×öµÄ£¬ËùÒÔÄã×îºÃÒ²²»ÀýÍâ¡£ µ«ÊÇ£¬µ±Äã²âÊÔÒ»¸öÄ£¿éʱ£¬ÔÚ¹¤×÷Ŀ¼½¨Á¢Ò»¸öÉ豸ÎļþÒ²²»´í¡£ Ö»Òª±£Ö¤Íê³Éºó½«Ëü·ÅÔÚÇý¶¯³ÌÐòÕҵõ½µÄµØ·½¡£
ÎÒ»¹ÏëÉùÃ÷ÔÚÒÔÉÏÌÖÂÛÖÐÒþº¬µÄ¼¸µã¡£µ±ÏµÍ³·ÃÎÊÒ»¸öϵͳÎļþʱ£¬ ϵͳÄÚºËֻʹÓÃÖ÷É豸ºÅÀ´Çø±ðÉ豸ÀàÐͺ;ö¶¨Ê¹ÓúÎÖÖÄÚºËÄ£¿é¡£ÏµÍ³ Äں˲¢²»ÐèÒªÖªµÀ´ÓÉ豸ºÅ¡£ÄÚºËÄ£¿éÇý¶¯±¾Éí²Å¹Ø×¢´ÓÉ豸ºÅ£¬²¢ÓÃÖ®À´ Çø±ðÆä²Ù×ݵIJ»Í¬É豸¡£
ÁíÍ⣬ÎÒÕâ¶ùÌáµ½µÄÓ²¼þÊDZÈÄÇÖÖ¿ÉÒÔÎÕÔÚÊÖÀïµÄPCI¿¨ÉÔ΢³éÏóÒ»µãµÄ¶«Î÷¡£¿´Ò»ÏÂÏÂÃæµÄÁ½¸öÉ豸Îļþ£º
% ls -l /dev/fd0 /dev/fd0u1680
brwxrwxrwx 1 root floppy 2, 0 Jul 5 2000 /dev/fd0
brw-rw---- 1 root floppy 2, 44 Jul 5 2000 /dev/fd0u1680
ÄãÏÖÔÚÁ¢¼´Ã÷°×ÕâÊÇ¿ìÉ豸µÄÉ豸Îļþ²¢ÇÒËüÃÇÊÇÓÐÏàͬµÄÇý¶¯ÄÚºËÄ£¿éÀ´²Ù×Ý £¨Ö÷É豸ºÅ¶¼Îª2)£©¡£ÄãÒ²ÐíÒ²Òâʶµ½ËüÃǶ¼ÊÇÄãµÄÈíÅÌÇý¶¯Æ÷£¬ ¼´Ê¹Äãʵ¼ÊÉÏÖ»ÓÐÒ»¸öÈíÅÌÇý¶¯Æ÷¡£ÎªÊ²Ã´ÊÇÁ½¸öÉ豸Îļþ£¿ÒòΪËüÃÇÆäÖеÄÒ»¸ö´ú±í×Å ÄãµÄ1.44 MBÈÝÁ¿µÄÈíÇý£¬ÁíÒ»¸ö´ú±í×ÅÄãµÄ1.68 MBÈÝÁ¿µÄ£¬±»Ä³Ð©È˳ÆΪ¡°³¬¼¶¸ñʽ»¯¡±µÄÈíÇý¡£ Õâ¾ÍÊÇÒ»¸ö²»Í¬µÄ´ÓÉ豸ºÅ´ú±í×ÅÏàͬӲ¼þÉ豸µÄÀý×Ó¡£ÇëÇå³þµÄÒâʶµ½ÎÒÃÇÌáµ½µÄÓ²¼þÓÐʱ ¿ÉÄÜÊǷdz£³éÏóµÄ¡£
Notes
[1] ÕâÊÇÒ»¸öÈ¥¸ú×Ù³ÌÐò¾¿¾¹ÔÚ×öʲôµÄ·Ç³£ÓмÛÖµµÄ¹¤¾ß¡£
[2] ÎÒÊÇÎïÀíרҵµÄ£¬ ¶ø²»ÊÇÖ÷ÐÞ¼ÆËã»ú¡£
[3] ÕⲻͬÓÚ½«ËùÓеÄÄÚºËÄ£¿é±àÒë½øÄںˣ¬µ«Òâ˼ȷʵÊÇÒ»ÑùµÄ¡£
febspeolal ÓÚ 2006-11-09 01:08:24·¢±í:
Chapter 2. Hello World
/* Needed by all modules */
/* Needed for KERN_ALERT */
/* Needed by all modules */
/* Needed for KERN_ALERT */
/* Needed for the macros */
/* Needed by all modules */
/* Needed for KERN_ALERT */
/* Needed for the macros */
<1st src file.o> <2nd src file.o>¡£
/* We're doing kernel work */
/* Specifically, a module */
/* We're doing kernel work */
/* Specifically, a module */
Table of Contents
Hello, World (part 1): ×î¼òµ¥µÄÄÚºËÄ£¿é
±àÒëÄÚºËÄ£¿é
Hello World (part 2)
Hello World (part 3): ¹ØÓÚ__initºÍ__exitºê
Hello World (part 4): ÄÚºËÄ£¿éÖ¤ÊéºÍÄÚºËÄ£¿éÎĵµËµÃ÷
´ÓÃüÁîÐд«µÝ²ÎÊý¸øÄÚºËÄ£¿é
Óɶà¸öÎļþ¹¹³ÉµÄÄÚºËÄ£¿é
ΪÒѱàÒëµÄÄں˱àÒëÄ£¿é
Hello, World (part 1): ×î¼òµ¥µÄÄÚºËÄ£¿é
µ±µÚÒ»¸ö¶´Ñ¨³ÌÐòÔ±ÔÚµÚһ̨¶´Ñ¨¼ÆËã»úµÄǽÉÏÉÏÔäдµÚÒ»¸ö³ÌÐòʱ£¬ ÕâÊÇÒ»¸öÔÚÁçÑòƤÉÏÊä³ö`Hello, world'µÄ×Ö·û´®¡£ÂÞÂíµÄ±à³ÌÊé¼®ÉÏÊÇÒÔ `Salut, Mundi'ÕâÑùµÄ³ÌÐò¿ªÊ¼µÄ¡£ ÎÒ²»Ã÷°×ÈËÃÇΪʲôҪÆÆ»µÕâ¸ö´«Í³£¬ µ«ÎÒÈÏΪ»¹ÊDz»Ã÷°×ΪºÃ¡£ÎÒÃǽ«´Ó±àдһϵÁеÄ`Hello, world'Ä£¿é¿ªÊ¼£¬ Ò»²½²½Õ¹Ê¾±àдÄÚºËÄ£¿éµÄ»ù´¡µÄ·½·½ÃæÃæ¡£
Õâ¿ÉÄÜÊÇÒ»¸ö×î¼òµ¥µÄÄ£¿éÁË¡£Ïȱð¼±×űàÒëËü¡£ÎÒÃǽ«ÔÚÏÂÕÂÄ£¿é±àÒëµÄÕ½ڽéÉÜÏà¹ØÄÚÈÝ¡£
Example 2-1. hello-1.c
/*
* hello-1.c - The simplest kernel module.
*/
#include
#include
int init_module(void)
{
printk("<1>Hello world 1.\n" );
/*
* A non 0 return means init_module failed; module can't be loaded.
*/
return 0;
}
void cleanup_module(void)
{
printk(KERN_ALERT "Goodbye world 1.\n" );
}
Ò»¸öÄÚºËÄ£¿éÓ¦¸ÃÖÁÉÙ°üº¬Á½¸öº¯Êý¡£Ò»¸ö¡°¿ªÊ¼¡±(³õʼ»¯)µÄº¯Êý±»³ÆΪinit_module() »¹ÓÐÒ»¸ö¡°½áÊø¡± (¸ÉһЩÊÕβÇåÀíµÄ¹¤×÷)µÄº¯Êý±»³ÆΪcleanup_module() £¬µ±ÄÚºËÄ£¿é±»rmmodжÔØʱ±»Ö´ÐС£Êµ¼ÊÉÏ£¬´ÓÄں˰汾2.3.13¿ªÊ¼ÕâÖÖÇé¿öÓÐЩ¸Ä±ä¡£ Äã¿ÉÒÔΪÄãµÄ¿ªÊ¼ºÍ½áÊøº¯ÊýÆðÈÎÒâµÄÃû×Ö¡£ Ä㽫ÔÚÒÔºóѧϰÈçºÎʵÏÖÕâÒ»µãthe Section called Hello World (part 2)¡£ ʵ¼ÊÉÏ£¬Õâ¸öз½·¨Ê±ÍƼöµÄʵÏÖ·½·¨¡£µ«ÊÇ£¬Ðí¶àÈËÈÔȻʹinit_module()ºÍ cleanup_module()×÷ΪËûÃǵĿªÊ¼ºÍ½áÊøº¯Êý¡£
Ò»°ã£¬init_module()ҪôÏòÄÚºË×¢²áËü¿ÉÒÔ´¦ÀíµÄÊÂÎҪôÓÃ×Ô¼ºµÄ´úÂë Ìæ´úij¸öÄں˺¯Êý(´úÂëͨ³£ÕâÑù×öÈ»ºóÔÙÈ¥µ÷ÓÃÔÏȵĺ¯Êý´úÂë)¡£º¯Êý cleanup_module()Ó¦¸Ã³·ÏûÈκÎinit_module()×öµÄÊ£¬´Ó¶ø ÄÚºËÄ£¿é¿ÉÒÔ±»°²È«µÄжÔØ¡£
×îºó£¬ÈÎÒ»¸öÄÚºËÄ£¿éÐèÒª°üº¬linux/module.h¡£ ÎÒÃǽö½öÐèÒª°üº¬ linux/kernel.hµ±ÐèҪʹÓà printk()¼Ç¼¼¶±ðµÄºêÀ©Õ¹Ê±KERN_ALERT£¬Ïà¹ØÄÚÈݽ«ÔÚthe Section called ½éÉÜprintk()ÖнéÉÜ¡£
½éÉÜprintk()
²»¹ÜÄã¿ÉÄÜÔõôÏ룬printk()²¢²»ÊÇÉè¼ÆÓÃÀ´Í¬Óû§½»»¥µÄ£¬ËäÈ»ÎÒÃÇÔÚ hello-1¾ÍÊdzöÓÚÕâÑùµÄÄ¿µÄʹÓÃËü£¡Ëüʵ¼ÊÉÏÊÇΪÄÚºËÌṩÈÕÖ¾¹¦ÄÜ£¬ ¼Ç¼ÄÚºËÐÅÏ¢»òÓÃÀ´¸ø³ö¾¯¸æ¡£Òò´Ë£¬Ã¿¸öprintk() ÉùÃ÷¶¼»á´øÒ»¸öÓÅÏȼ¶£¬¾ÍÏñÄã¿´µ½µÄ<1>ºÍKERN_ALERT ÄÇÑù¡£ÄÚºË×ܹ²¶¨ÒåÁ˰˸öÓÅÏȼ¶µÄºê£¬ ËùÒÔÄã²»±ØʹÓûÞɬµÄÊý×Ö´úÂ룬²¢ÇÒÄã¿ÉÒÔ´ÓÎļþ linux/kernel.h²é¿´ÕâЩºêºÍËüÃǵÄÒâÒå¡£Èç¹ûÄã ²»Ö¸Ã÷ÓÅÏȼ¶£¬Ä¬ÈϵÄÓÅÏȼ¶DEFAULT_MESSAGE_LOGLEVEL½«±»²ÉÓá£
ÔĶÁÒ»ÏÂÕâЩÓÅÏȼ¶µÄºê¡£Í·ÎļþͬʱҲÃèÊöÁËÿ¸öÓÅÏȼ¶µÄÒâÒå¡£ÔÚʵ¼ÊÖУ¬ ʹÓúê¶ø²»ÒªÊ¹ÓÃÊý×Ö£¬¾ÍÏñ<4>¡£×ÜÊÇʹÓú꣬¾ÍÏñ KERN_WARNING¡£
µ±ÓÅÏȼ¶µÍÓÚint console_loglevel£¬ÐÅÏ¢½«Ö±½Ó´òÓ¡ÔÚÄãµÄÖÕ¶ËÉÏ¡£Èç¹ûͬʱ syslogdºÍklogd¶¼ÔÚÔËÐУ¬ÐÅϢҲͬʱÌí¼ÓÔÚÎļþ /var/log/messages£¬¶ø²»¹ÜÊÇ·ñÏÔʾÔÚ¿ØÖÆ̨ÉÏÓë·ñ¡£ÎÒÃÇʹÓÃÏñ KERN_ALERTÕâÑùµÄ¸ßÓÅÏȼ¶£¬À´È·±£printk()½«ÐÅÏ¢Êä³öµ½ ¿ØÖÆ̨¶ø²»ÊÇÖ»ÊÇÌí¼Óµ½ÈÕÖ¾ÎļþÖС£ µ±Äã±àдÕæÕýµÄʵÓõÄÄ£¿éʱ£¬ÄãÓ¦¸ÃÕë¶Ô¿ÉÄÜÓöµ½µÄÇé¿öʹÓÃºÏ ÊʵÄÓÅÏȼ¶¡£
±àÒëÄÚºËÄ£¿é
ÄÚºËÄ£¿éÔÚÓÃgcc±àÒëʱÐèҪʹÓÃÌض¨µÄ²ÎÊý¡£ÁíÍ⣬һЩºêͬÑùÐèÒª¶¨Òå¡£ ÕâÊÇÒòΪÔÚ±àÒë³É¿ÉÖ´ÐÐÎļþºÍÄÚºËÄ£¿éʱ£¬ ÄÚºËÍ·ÎļþÆðµÄ×÷ÓÃÊDz»Í¬µÄ¡£ ÒÔÍùµÄÄں˰汾ÐèÒªÎÒÃÇÈ¥ÔÚMakefileÖÐÊÖ¶¯ÉèÖÃÕâЩÉ趨¡£¾¡¹ÜÕâЩMakefileÊÇ°´Ä¿Â¼·Ö²ã´Î °²Åŵģ¬µ«ÊÇÕâÆäÖÐÓÐÐí¶à¶àÓàµÄÖظ´²¢µ¼Ö´úÂëÊ÷´ó¶øÄÑÒÔά»¤¡£ ÐÒÔ˵ÄÊÇ£¬Ò»ÖÖ³ÆΪkbuildµÄз½·¨±»ÒýÈ룬ÏÖÔÚÍⲿµÄ¿É¼ÓÔØÄÚºËÄ£¿éµÄ±àÒëµÄ·½·¨ÒѾͬÄں˱àÒëͳһÆðÀ´¡£ÏëÁ˽â¸ü¶àµÄ±à Òë·ÇÄں˴úÂëÊ÷ÖеÄÄ£¿é(¾ÍÏñÎÒÃǽ«Òª±àдµÄ)Çë²Î¿¼°ïÖúÎļþlinux/Documentation/kbuild/modules.txt¡£
ÏÖÔÚÈÃÎÒÃÇ¿´Ò»¸ö±àÒëÃû×Ö½Ð×öhello-1.cµÄÄ£¿éµÄ¼òµ¥µÄMakefileÎļþ£º
Example 2-2. Ò»¸ö»ù±¾µÄMakefile
obj-m += hello-1.o
ÏÖÔÚÄã¿ÉÒÔͨ¹ýÖ´ÐÐÃüÁî make -C /usr/src/linux-`uname -r` SUBDIRS=$PWD modules ±àÒëÄ£¿é¡£ ÄãÓ¦¸ÃµÃµ½Í¬ÏÂÃæÀàËƵÄÆÁÄ»Êä³ö£º
[root@pcsenonsrv test_module]# make -C /usr/src/linux-`uname -r` SUBDIRS=$PWD modules
make: Entering directory `/usr/src/linux-2.6.x
CC [M] /root/test_module/hello-1.o
Building modules, stage 2.
MODPOST
CC /root/test_module/hello-1.mod.o
LD [M] /root/test_module/hello-1.ko
make: Leaving directory `/usr/src/linux-2.6.x
Çë×¢Òâ2.6µÄÄÚºËÏÖÔÚÒýÈëÒ»ÖÖеÄÄÚºËÄ£¿éÃüÃû¹æ·¶£ºÄÚºËÄ£¿éÏÖÔÚʹÓÃ.koµÄÎļþºó׺(´úÌæ ÒÔÍùµÄ.oºó׺)£¬ÕâÑùÄÚºËÄ£¿é¾Í¿ÉÒÔͬÆÕͨµÄÄ¿±êÎļþÇø±ð¿ª¡£¸üÏêϸµÄÎĵµÇë²Î¿¼ linux/Documentation/kbuild/makefiles.txt¡£ÔÚÑо¿Makefile֮ǰÇëÈ·ÈÏÄãÒѾ²Î¿¼ÁËÕâЩÎĵµ¡£
ÏÖÔÚÊÇʹÓÃinsmod ./hello-1.koÃüÁî¼ÓÔظÃÄ£¿éµÄʱºòÁË(ºöÂÔÈκÎÄã¿´µ½µÄ¹ØÓÚÄÚºËÎÛȾµÄÊä³ö ÏÔʾ£¬ÎÒÃǽ«ÔÚÒÔºó½éÉÜÏà¹ØÄÚÈÝ)¡£
ËùÓÐÒѾ±»¼ÓÔصÄÄÚºËÄ£¿é¶¼ÂÞÁÐÔÚÎļþ/proc/modulesÖС£catÒ»ÏÂÕâ¸öÎļþ¿´Ò»ÏÂÄãµÄÄ£¿éÊÇ·ñÕæµÄ ³ÉΪÄں˵ÄÒ»²¿·ÖÁË¡£Èç¹ûÊÇ£¬×£ºØÄ㣡ÄãÏÖÔÚÒѾÊÇÄÚºËÄ£¿éµÄ×÷ÕßÁË¡£µ±ÄãµÄÐÂÏʾ¢¹ýÈ¥ºó£¬Ê¹ÓÃÃüÁî rmmod hello-1.жÔØÄ£¿é¡£ÔÙ¿´Ò»ÏÂ/var/log/messagesÎļþµÄÄÚÈÝÊÇ·ñÓÐÏà¹ØµÄÈÕÖ¾ÄÚÈÝ¡£
Õâ¶ùÊÇÁíÒ»¸öÁ·Ï°¡£¿´µ½ÁËÔÚÉùÃ÷ init_module()ÉϵÄ×¢ÊÍÂð? ¸Ä±ä·µ»ØÖµ·ÇÁ㣬ÖØбàÒëÔÙ¼ÓÔØ£¬·¢ÉúÁËʲô£¿
Hello World (part 2)
ÔÚÄÚºËLinux 2.4ÖУ¬Äã¿ÉÒÔΪÄãµÄÄ£¿éµÄ¡°¿ªÊ¼¡±ºÍ¡°½áÊø¡±º¯ÊýÆðÈÎÒâµÄÃû×Ö¡£ËüÃDz»ÔÙ±ØÐëʹÓà init_module()ºÍcleanup_module()µÄÃû×Ö¡£Õâ¿ÉÒÔͨ¹ýºê module_init()ºÍmodule_exit()ʵÏÖ¡£ÕâЩºêÔÚÍ·Îļþlinux/init.h¶¨Ò塣ΨһÐèҪעÒâµÄµØ·½ÊǺ¯Êý±ØÐëÔÚºêµÄʹÓÃÇ°¶¨Ò壬·ñÔò»áÓбàÒë ´íÎó¡£ÏÂÃæ¾ÍÊÇÒ»¸öÀý×Ó¡£
Example 2-3. hello-2.c
/*
* hello-2.c - Demonstrating the module_init() and module_exit() macros.
* This is preferred over using init_module() and cleanup_module().
*/
#include
#include
#include
static int __init hello_2_init(void)
{
printk(KERN_ALERT "Hello, world 2\n" );
return 0;
}
static void __exit hello_2_exit(void)
{
printk(KERN_ALERT "Goodbye, world 2\n" );
}
module_init(hello_2_init);
module_exit(hello_2_exit);
ÏÖÔÚÎÒÃÇÒѾд¹ýÁ½¸öÕæÕýµÄÄ£¿éÁË¡£Ìí¼Ó±àÒëÁíÒ»¸öÄ£¿éµÄÑ¡ÏîÊ®·Ö¼òµ¥£¬ÈçÏ£º
Example 2-4. Á½¸öÄÚºËÄ£¿éʹÓõÄMakefile
obj-m += hello-1.o
obj-m += hello-2.o
ÏÖÔÚÈÃÎÒÃÇÀ´Ñо¿Ò»ÏÂlinux/drivers/char/MakefileÕâ¸öʵ¼ÊÖеÄÀý×Ó¡£¾ÍÈçͬÄã¿´µ½µÄ£¬ һЩ±»±àÒë½øÄÚºË (obj-y)£¬µ«ÊÇÕâЩobj-mÄÄÀïÈ¥ÁËÄØ£¿¶ÔÓÚÊìϤshell½Å±¾µÄÈËÕâ²»ÄÑÀí½â¡£ÕâЩÔÚMakefileÖÐËæ´¦¿É¼û µÄobj-$(CONFIG_FOO)µÄÖ¸Á»áÔÚCONFIG_FOO±»ÉèÖúóÀ©Õ¹ÎªÄãÊìϤµÄobj-y»òobj-m¡£ÕâÆäʵ¾ÍÊÇÄãÔÚʹÓà make menuconfig±àÒëÄÚºËʱÉú³ÉµÄlinux/.configÖÐÉèÖõĶ«Î÷¡£
Hello World (part 3): ¹ØÓÚ__initºÍ__exitºê
ÕâÀïչʾÁËÄÚºË2.2ÒÔºóÒýÈëµÄÒ»¸öÐÂÌØÐÔ¡£×¢ÒâÔÚ¸ºÔð¡°³õʼ»¯¡±ºÍ¡°ÇåÀíÊÕβ¡±µÄº¯Êý¶¨Òå´¦µÄ±ä»¯¡£ºê __initµÄʹÓûáÔÚ³õʼ»¯Íê³Éºó¶ªÆú¸Ãº¯Êý²¢ÊÕ»ØËùÕ¼Äڴ棬Èç¹û¸ÃÄ£¿é±»±àÒë½øÄںˣ¬¶ø²»ÊǶ¯Ì¬¼ÓÔØ¡£
ºê__initdataͬ__init ÀàËÆ£¬Ö»²»¹ý¶Ô±äÁ¿ÓÐЧ¡£
ºê__exit½«ºöÂÔ¡°ÇåÀíÊÕβ¡±µÄº¯ÊýÈç¹û¸ÃÄ£¿é±»±àÒë½øÄںˡ£Í¬ºê __exitÒ»Ñù£¬¶Ô¶¯Ì¬¼ÓÔØÄ£¿éÊÇÎÞЧµÄ¡£ÕâºÜÈÝÒ×Àí½â¡£±àÒë½øÄں˵ÄÄ£¿é ÊÇûÓÐÇåÀíÊÕβ¹¤×÷µÄ, ¶ø¶¯Ì¬¼ÓÔصÄÈ´ÐèÒª×Ô¼ºÍê³ÉÕâЩ¹¤×÷¡£
ÕâЩºêÔÚÍ·Îļþlinux/init.h¶¨Ò壬ÓÃÀ´ÊÍ·ÅÄÚºËÕ¼ÓõÄÄÚ´æ¡£ µ±ÄãÔÚÆô¶¯Ê±¿´µ½ÕâÑùµÄFreeing unused kernel memory: 236k freedÄÚºËÊä³ö£¬ÉÏÃæµÄ ÄÇЩÕýÊÇÄÚºËËùÊͷŵġ£
Example 2-5. hello-3.c
/*
* hello-3.c - Illustrating the __init, __initdata and __exit macros.
*/
#include
#include
#include
static int hello3_data __initdata = 3;
static int __init hello_3_init(void)
{
printk(KERN_ALERT "Hello, world %d\n", hello3_data);
return 0;
}
static void __exit hello_3_exit(void)
{
printk(KERN_ALERT "Goodbye, world 3\n" );
}
module_init(hello_3_init);
module_exit(hello_3_exit);
Hello World (part 4): ÄÚºËÄ£¿éÖ¤ÊéºÍÄÚºËÄ£¿éÎĵµËµÃ÷
Èç¹ûÄãÔÚʹÓÃ2.4»ò¸üеÄÄںˣ¬µ±Äã¼ÓÔØÄãµÄÄ£¿éʱ£¬ÄãÒ²Ðí×¢Òâµ½ÁËÕâЩÊä³öÐÅÏ¢£º
# insmod hello-3.o
Warning: loading hello-3.o will taint the kernel: no license
See http://www.tux.org/lkml/#export-tainted for information about tainted modules
Hello, world 3
Module hello-3 loaded, with warnings
ÔÚ2.4»ò¸üеÄÄÚºËÖУ¬Ò»ÖÖʶ±ð´úÂëÊÇ·ñÔÚGPLÐí¿ÉÏ·¢²¼µÄ»úÖƱ»ÒýÈ룬 Òò´ËÈËÃÇ¿ÉÒÔÔÚʹÓ÷ǹ«¿ªµÄÔ´´úÂë²úƷʱµÃµ½¾¯¸æ¡£Õâͨ¹ýÔÚÏÂÒ»ÕÂչʾµÄºê MODULE_LICENSE()µ±ÄãÉèÖÃÔÚGPLÖ¤ÊéÏ·¢²¼ÄãµÄ´úÂëʱ£¬ Äã¿ÉÒÔÈ¡ÏûÕâЩ¾¯¸æ¡£ÕâÖÖÖ¤Êé»úÖÆÔÚÍ·Îļþlinux/module.h ʵÏÖ£¬Í¬Ê±»¹ÓÐһЩÏà¹ØÎĵµÐÅÏ¢¡£
/*
* The following license idents are currently accepted as indicating free
* software modules
*
* "GPL " [GNU Public License v2 or later]
* "GPL v2 " [GNU Public License v2]
* "GPL and additional rights" [GNU Public License v2 rights and more]
* "Dual BSD/GPL " [GNU Public License v2
* or BSD license choice]
* "Dual MPL/GPL " [GNU Public License v2
* or Mozilla license choice]
*
* The following other idents are available
*
* " Proprietary" [Non free products]
*
* There are dual licensed components, but when running with Linux it is the
* GPL that is relevant so this is a non issue. Similarly LGPL linked with GPL
* is a GPL combined work.
*
* This exists for several reasons
* 1. So modinfo can show license info for users wanting to vet their setup
* is free
* 2. So the community can ignore bug reports including proprietary modules
* 3. So vendors can do likewise based on their own policies
*/
ÀàËƵģ¬ºêMODULE_DESCRIPTION()ÓÃÀ´ÃèÊöÄ£¿éµÄÓÃ;¡£ ºêMODULE_AUTHOR()ÓÃÀ´ÉùÃ÷Ä£¿éµÄ×÷Õß¡£ºêMODULE_SUPPORTED_DEVICE() ÉùÃ÷Ä£¿éÖ§³ÖµÄÉ豸¡£
ÕâЩºê¶¼ÔÚÍ·Îļþlinux/module.h¶¨Ò壬 ²¢ÇÒÄں˱¾Éí²¢²»Ê¹ÓÃÕâЩºê¡£ËüÃÇÖ»ÊÇÓÃÀ´Ìṩʶ±ðÐÅÏ¢£¬¿ÉÓù¤¾ß³ÌÐòÏñobjdump²é¿´¡£ ×÷Ϊһ¸öÁ·Ï°£¬Ê¹ÓÃgrep´ÓĿ¼linux/drivers¿´Ò»¿´ÕâЩģ¿éµÄ×÷ÕßÊÇÈçºÎ ΪËûÃǵÄÄ£¿éÌṩʶ±ðÐÅÏ¢ºÍµµ°¸µÄ¡£
Example 2-6. hello-4.c
/*
* hello-4.c - Demonstrates module documentation.
*/
#include
#include
#include
#define DRIVER_AUTHOR " Peter Jay Salzman <p@dirac.org>"
#define DRIVER_DESC "A sample driver"
static int __init init_hello_4(void)
{
printk(KERN_ALERT "Hello, world 4\n" );
return 0;
}
static void __exit cleanup_hello_4(void)
{
printk(KERN_ALERT "Goodbye, world 4\n" );
}
module_init(init_hello_4);
module_exit(cleanup_hello_4);
/*
* You can use strings, like this:
*/
/*
* Get rid of taint message by declaring code as GPL.
*/
MODULE_LICENSE("GPL" );
/*
* Or with defines, like this:
*/
MODULE_AUTHOR(DRIVER_AUTHOR ); /* Who wrote this module? */
MODULE_DESCRIPTION(DRIVER_DESC ); /* What does this module do */
/*
* This module uses /dev/testdevice. The MODULE_SUPPORTED_DEVICE macro might
* be used in the future to help automatic configuration of modules, but is
* currently unused other than for documentation purposes.
*/
MODULE_SUPPORTED_DEVICE("testdevice" );
´ÓÃüÁîÐд«µÝ²ÎÊý¸øÄÚºËÄ£¿é
Ä£¿éÒ²¿ÉÒÔ´ÓÃüÁîÐлñÈ¡²ÎÊý¡£µ«²»ÊÇͨ¹ýÒÔÇ°ÄãÏ°¹ßµÄargc/argv¡£
Òª´«µÝ²ÎÊý¸øÄ£¿é£¬Ê×ÏȽ«»ñÈ¡²ÎÊýÖµµÄ±äÁ¿ÉùÃ÷Ϊȫ¾Ö±äÁ¿¡£È»ºóʹÓúêMODULE_PARM()(ÔÚÍ·Îļþlinux/module.h)¡£ÔËÐÐʱ£¬insmod½«¸ø±äÁ¿¸³ÓèÃüÁîÐеIJÎÊý£¬Èçͬ ./insmod mymodule.o myvariable=5¡£ÎªÊ¹´úÂëÇåÎú£¬±äÁ¿µÄÉùÃ÷ºÍºê¶¼Ó¦¸Ã·ÅÔÚ Ä£¿é´úÂëµÄ¿ªÊ¼²¿·Ö¡£ÒÔϵĴúÂë·¶ÀýÒ²Ðí½«±ÈÎÒ¹«ÈϲµÄ½â˵¸üºÃ¡£
ºêMODULE_PARM()ÐèÒªÁ½¸ö²ÎÊý£¬±äÁ¿µÄÃû×ÖºÍÆäÀàÐÍ¡£Ö§³ÖµÄÀàÐÍÓÐ" b": ±ÈÌØÐÍ£¬"h": ¶ÌÕûÐÍ, "i": ÕûÊýÐÍ£¬" l: ³¤ÕûÐÍºÍ "s": ×Ö·û´®ÐÍ,ÆäÖÐÕýÊýÐͼȿÉΪsignedÒ²¿ÉΪunsigned¡£ ×Ö·û´®ÀàÐÍÓ¦¸ÃÉùÃ÷Ϊ"char *"ÕâÑùinsmod¾Í¿ÉÒÔΪËüÃÇ·ÖÅäÄÚ´æ¿Õ¼ä¡£ÄãÓ¦¸Ã×ÜÊÇΪÄãµÄ±äÁ¿¸³³õÖµ¡£ ÕâÊÇÄں˱à³Ì£¬´úÂëÒª±àдµÄÊ®·Ö½÷É÷¡£¾Ù¸öÀý×Ó£º
int myint = 3;
char *mystr;
MODULE_PARM(myint, "i" );
MODULE_PARM(mystr, "s" );
Êý×éͬÑù±»Ö§³Ö¡£ÔÚºêMODULE_PARMÖÐÔÚÀàÐÍ·ûºÅÇ°ÃæµÄÕûÐÍÖµÒâζ×ÅÒ»¸öÖ¸¶¨ÁË×î´ó³¤¶ÈµÄÊý×é¡£ ÓÃ'-'¸ô¿ªµÄÁ½¸öÊý×ÖÔò·Ö±ðÒâζ×Å×îСºÍ×î´ó³¤¶È¡£ÏÂÃæµÄÀý×ÓÖУ¬¾ÍÉùÃ÷ÁËÒ»¸ö×îС³¤¶ÈΪ2,×î´ó³¤¶ÈΪ4µÄÕûÐÎÊý×é¡£
int myshortArray[4];
MODULE_PARM (myintArray, "3-9i" );
½«³õʼֵÉèΪȱʡʹÓõÄIO¶Ë¿Ú»òIOÄÚ´æÊÇÒ»¸ö²»´íµÄ×÷·¨¡£Èç¹ûÕâЩ±äÁ¿ÓÐȱʡֵ£¬Ôò¿ÉÒÔ½øÐÐ×Ô¶¯É豸¼ì²â£¬ ·ñÔò±£³Öµ±Ç°ÉèÖõÄÖµ¡£ÎÒÃǽ«ÔÚºóÐøÕ½ڽâÊÍÇå³þÏà¹ØÄÚÈÝ¡£ÔÚÕâÀïÎÒÖ»ÊÇÑÝʾÈçºÎÏòÒ»¸öÄ£¿é´«µÝ²ÎÊý¡£
×îºó£¬»¹ÓÐÕâÑùÒ»¸öºê£¬MODULE_PARM_DESC()±»ÓÃÀ´×¢½â¸ÃÄ£¿é¿ÉÒÔ½ÓÊյIJÎÊý¡£¸Ãºê Á½¸ö²ÎÊý£º±äÁ¿ÃûºÍÒ»¸ö¸ñʽ×ÔÓɵĶԸñäÁ¿µÄÃèÊö¡£
Example 2-7. hello-5.c
/*
* hello-5.c - Demonstrates command line argument passing to a module.
*/
#include
#include
#include
#include
#include
MODULE_LICENSE("GPL" );
MODULE_AUTHOR(" Peter Jay Salzman" );
static short int myshort = 1;
static int myint = 420;
static long int mylong = 9999;
static char *mystring = "blah";
/*
* module_param(foo, int, 0000)
* The first param is the parameters name
* The second param is it's data type
* The final argument is the permissions bits,
* for exposing parameters in sysfs (if non-zero) at a later stage.
*/
module_param(myshort, short, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP);
MODULE_PARM_DESC(myshort, "A short integer" );
module_param(myint, int, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
MODULE_PARM_DESC(myint, "An integer" );
module_param(mylong, long, S_IRUSR);
MODULE_PARM_DESC(mylong, "A long integer" );
module_param(mystring, charp, 0000);
MODULE_PARM_DESC(mystring, "A character string" );
static int __init hello_5_init(void)
{
printk(KERN_ALERT "Hello, world 5\n=============\n" );
printk(KERN_ALERT "myshort is a short integer: %hd\n", myshort);
printk(KERN_ALERT "myint is an integer: %d\n", myint);
printk(KERN_ALERT "mylong is a long integer: %ld\n", mylong);
printk(KERN_ALERT "mystring is a string: %s\n", mystring);
return 0;
}
static void __exit hello_5_exit(void)
{
printk(KERN_ALERT "Goodbye, world 5\n" );
}
module_init(hello_5_init);
module_exit(hello_5_exit);
ÎÒ½¨ÒéÓÃÏÂÃæµÄ·½·¨ÊµÑéÄãµÄÄ£¿é£º
satan# insmod hello-5.o mystring="bebop" mybyte=255 myintArray=-1
mybyte is an 8 bit integer: 255
myshort is a short integer: 1
myint is an integer: 20
mylong is a long integer: 9999
mystring is a string: bebop
myintArray is -1 and 420
satan# rmmod hello-5
Goodbye, world 5
satan# insmod hello-5.o mystring="supercalifragilisticexpialidocious" \
> mybyte=256 myintArray=-1,-1
mybyte is an 8 bit integer: 0
myshort is a short integer: 1
myint is an integer: 20
mylong is a long integer: 9999
mystring is a string: supercalifragilisticexpialidocious
myintArray is -1 and -1
satan# rmmod hello-5
Goodbye, world 5
satan# insmod hello-5.o mylong=hello
hello-5.o: invalid argument syntax for mylong: 'h'
Óɶà¸öÎļþ¹¹³ÉµÄÄÚºËÄ£¿é
ÓÐʱ½«Ä£¿éµÄÔ´´úÂë·ÖΪ¼¸¸öÎļþÊÇÒ»¸öÃ÷ÖǵÄÑ¡Ôñ¡£ÔÚÕâÖÖÇé¿öÏ£¬ÄãÐèÒª£º
Ö»ÒªÔÚÒ»¸öÔ´ÎļþÖÐÌí¼Ó#define __NO_VERSION__Ô¤´¦ÀíÃüÁî¡£ ÕâºÜÖØÒªÒòΪmodule.hͨ³£°üº¬ kernel_versionµÄ¶¨Ò壬´Ëʱһ¸ö´æ´¢×ÅÄں˰汾µÄÈ«¾Ö±äÁ¿½«»á±»±àÒë¡£µ«Èç¹û´ËʱÄãÓÖÒª°üº¬Í·Îļþ version.h£¬Äã±ØÐëÊÖ¶¯°üº¬Ëü£¬ÒòΪ module.h²»»áÔÙ°üº¬ËüÈç¹û´ò¿ªÔ¤´¦ÀíÑ¡Ïî__NO_VERSION__¡£
Ïñͨ³£Ò»Ñù±àÒë¡£
½«ËùÓеÄÄ¿±êÎļþÁ¬½ÓΪһ¸öÎļþ¡£ÔÚx86ƽ̨Ï£¬Ê¹ÓÃÃüÁîld -m elf_i386 -r -o
´ËʱMakefileÒ»Èç¼ÈÍù»á°ïÎÒÃÇÍê³É±àÒëºÍÁ¬½ÓµÄÔà»î¡£
ÕâÀïÊÇÕâÑùµÄÒ»¸öÄ£¿é·¶Àý¡£
Example 2-8. start.c
/*
* start.c - Illustration of multi filed modules
*/
#include
#include
int init_module(void)
{
printk("Hello, world - this is the kernel speaking\n" );
return 0;
}
ÁíÒ»¸öÎļþ£º
Example 2-9. stop.c
/*
* stop.c - Illustration of multi filed modules
*/
#include
#include
void cleanup_module()
{
printk("<1>Short is the life of a kernel module\n" );
}
×îºóÊǸÃÄ£¿éµÄMakefile£º
Example 2-10. Makefile
obj-m += hello-1.o
obj-m += hello-2.o
obj-m += hello-3.o
obj-m += hello-4.o
obj-m += hello-5.o
obj-m += startstop.o
startstop-objs := start.o stop.o
ΪÒѱàÒëµÄÄں˱àÒëÄ£¿é
ºÜÏÔÈ»£¬ÎÒÃÇÇ¿ÁÒÍƼöÄã±àÒëÒ»¸öеÄÄںˣ¬ÕâÑùÄã¾Í¿ÉÒÔ´ò¿ªÄÚºËÖÐһЩÓÐÓõÄÅÅ´í¹¦ÄÜ£¬ÏñÇ¿ÖÆжÔØÄ£¿é(MODULE_FORCE_UNLOAD)£º µ±¸ÃÑ¡Ïî±»´ò¿ªÊ±£¬Äã¿ÉÒÔrmmod -f moduleÇ¿ÖÆÄÚºËжÔØÒ»¸öÄ£¿é£¬¼´Ê¹ÄÚºËÈÏΪÕâÊDz»°²È«µÄ¡£¸ÃÑ¡Ïî¿ÉÒÔΪÄã½ÚÊ¡²»ÉÙ¿ª·¢Ê±¼ä¡£
µ«ÊÇ£¬ÄãÈÔÈ»ÓÐÐí¶àʹÓÃÒ»¸öÕýÔÚÔËÐÐÖеÄÒѱàÒëµÄÄں˵ÄÀíÓÉ¡£ÀýÈ磬ÄãûÓбàÒëºÍ°²×°ÐÂÄں˵ÄȨÏÞ£¬»òÕßÄ㲻ϣÍûÖØÆôÄãµÄ»úÆ÷À´ÔËÐÐÐÂÄںˡ£ Èç¹ûÄã¿ÉÒÔºÁÎÞ×谵ıàÒëºÍʹÓÃÒ»¸öеÄÄںˣ¬Äã¿ÉÒÔÌø¹ýʣϵÄÄÚÈÝ£¬È¨µ±ÊÇÒ»¸ö½Å×¢¡£
Èç¹ûÄã½ö½öÊÇ°²×°ÁËÒ»¸öеÄÄں˴úÂëÊ÷²¢ÓÃËüÀ´±àÒëÄãµÄÄ£¿é£¬µ±Äã¼ÓÔØÄãµÄÄ£¿éʱ£¬ÄãºÜ¿ÉÄÜ»áµÃµ½ÏÂÃæµÄ´íÎóÌáʾ£º
insmod: error inserting 'poet_atkm.ko': -1 Invalid module format
һЩ²»ÄÇôÉñÃصÄÐÅÏ¢±»¼Í¼ÔÚÎļþ/var/log/messagesÖУ»
Jun 4 22:07:54 localhost kernel: poet_atkm: version magic '2.6.5-1.358custom 686
REGPARM 4KSTACKS gcc-3.3' should be '2.6.5-1.358 686 REGPARM 4KSTACKS gcc-3.3'
»»¾ä»°Ëµ£¬Äں˾ܾø¼ÓÔØÄãµÄÄ£¿éÒòΪ¼ÇÔØ°æ±¾ºÅµÄ×Ö·û´®²»·û(¸üÈ·ÇеÄ˵ÊÇ°æ±¾Ó¡´Á)¡£°æ±¾Ó¡´Á×÷Ϊһ¸ö¾²Ì¬µÄ×Ö·û´®´æÔÚÓÚÄÚºËÄ£¿éÖУ¬ÒÔ vermagic:¡£ °æ±¾ÐÅÏ¢ÊÇÔÚÁ¬½Ó½×¶Î´ÓÎļþinit/vermagic.oÖлñµÃµÄ¡£ ²é¿´°æ±¾Ó¡´ÁºÍÆäËüÔÚÄ£¿éÖеÄһЩ×Ö·ûÐÅÏ¢£¬¿ÉÒÔʹÓÃÏÂÃæµÄÃüÁî modinfo module.ko£º
[root@pcsenonsrv 02-HelloWorld]# modinfo hello-4.ko
license: GPL
author: Peter Jay Salzman <p@dirac.org>
description: A sample driver
vermagic: 2.6.5-1.358 686 REGPARM 4KSTACKS gcc-3.3
depends:
ÎÒÃÇ¿ÉÒÔ½èÖúÑ¡Ïî--force-vermagic½â¾ö¸ÃÎÊÌ⣬µ«ÕâÖÖ·½·¨ÓÐDZÔÚµÄΣÏÕ£¬ËùÒÔÔÚ³ÉÊìµÄÄ£¿éÖÐÒ²ÊDz»¿É½ÓÊܵġ£ ½â¾ö·½·¨ÊÇÎÒÃǹ¹½¨Ò»¸öͬÎÒÃÇÔ¤ÏȱàÒëºÃµÄÄÚºËÍêÈ«ÏàͬµÄ±àÒë»·¾³¡£ÈçºÎ¾ßÌåʵÏÖ½«ÊǸÃÕºóÃæµÄÄÚÈÝ¡£
Ê×ÏÈ£¬×¼±¸Í¬ÄãÄ¿Ç°µÄÄں˰汾ÍêÈ«Ò»ÖµÄÄں˴úÂëÊ÷¡£È»ºó£¬ÕÒµ½ÄãµÄµ±Ç°Äں˵ıàÒëÅäÖÃÎļþ¡£Í¨³£Ëü¿ÉÒÔÔÚ·¾¶ /bootÏÂÕÒµ½£¬Ê¹ÓÃÏñconfig-2.6.xµÄÎļþÃû¡£Äã¿ÉÒÔÖ±½Ó½«Ëü¿½±´µ½Äں˴úÂëÊ÷µÄ·¾¶Ï£º cp /boot/config-`uname -r` /usr/src/linux-`uname -r`/.config¡£
ÈÃÎÒÃÇÔÙ´Î×¢ÒâÒ»ÏÂÏÈÇ°µÄ´íÎóÐÅÏ¢£º×Ðϸ¿´µÄ»°Äã»á·¢ÏÖ£¬¼´Ê¹Ê¹ÓÃÍêÈ«ÏàͬµÄÅäÖÃÎļþ£¬°æ±¾Ó¡´Á»¹ÊÇÓÐϸСµÄ²îÒìµÄ£¬µ«Õâ×ãÒÔµ¼Ö ģ¿é¼ÓÔصÄʧ°Ü¡£ÕâÆäÖеIJîÒì¾ÍÊÇÔÚÄ£¿éÖгöÏÖÈ´²»ÔÚÄÚºËÖгöÏÖµÄcustom×Ö·û´®£¬ÊÇÓÉijЩ·¢ÐаæÌṩµÄÐ޸ĹýµÄ makefileµ¼Öµġ£¼ì²é/usr/src/linux/Makefile£¬È·±£ÏÂÃæÕâЩÌض¨µÄ°æ±¾ÐÅϢͬÄãʹÓõÄÄÚºËÍêÈ«Ò»Ö£º
VERSION = 2
PATCHLEVEL = 6
SUBLEVEL = 5
EXTRAVERSION = -1.358custom
...
ÏñÉÏÃæµÄÇé¿öÄã¾ÍÐèÒª½«EXTRAVERSIONÒ»Ïî¸ÄΪ-1.358¡£ÎÒÃǵĽ¨ÒéÊǽ«ÔʼµÄmakefile±¸·ÝÔÚ /lib/modules/2.6.5-1.358/buildÏ¡£ Ò»¸ö¼òµ¥µÄÃüÁîcp /lib/modules/`uname -r`/build/Makefile /usr/src/linux-`uname -r`¼´¿É¡£ ÁíÍ⣬Èç¹ûÄãÒѾÔÚÔËÐÐÒ»¸öÓÉÉÏÃæµÄ´íÎóµÄMakefile±àÒëµÄÄںˣ¬ÄãÓ¦¸ÃÖØÐÂÖ´ÐÐ make£¬»òÖ±½Ó¶ÔÓ¦/lib/modules/2.6.x/build/include/linux/version.h´ÓÎļþ /usr/src/linux-2.6.x/include/linux/version.hÐÞ¸ÄUTS_RELEASE£¬»òÓÃÇ°Õ߸²¸ÇºóÕߵġ£
ÏÖÔÚ£¬ÇëÖ´ÐÐmakeÀ´¸üÐÂÉèÖúͰ汾Ïà¹ØµÄÍ·Îļþ£¬Ä¿±êÎļþ£º
[root@pcsenonsrv linux-2.6.x]# make
CHK include/linux/version.h
UPD include/linux/version.h
SYMLINK include/asm -> include/asm-i386
SPLIT include/linux/autoconf.h -> include/config/*
HOSTCC scripts/basic/fixdep
HOSTCC scripts/basic/split-include
HOSTCC scripts/basic/docproc
HOSTCC scripts/conmakehash
HOSTCC scripts/kallsyms
CC scripts/empty.o
...
Èç¹ûÄã²»ÊÇȷʵÏë±àÒëÒ»¸öÄںˣ¬Äã¿ÉÒÔÔÚSPLITºóͨ¹ý°´ÏÂCTRL-CÖÐÖ¹±àÒë¹ý³Ì¡£ÒòΪ´ËʱÄãÐèÒªµÄÎļþ ÒѾ¾ÍÐ÷ÁË¡£ÏÖÔÚÄã¿ÉÒÔ·µ»ØÄãµÄÄ£¿éĿ¼Ȼºó±àÒë¼ÓÔØËü£º´Ëʱģ¿é½«ÍêÈ«Õë¶ÔÄãµÄµ±Ç°Äں˱àÒ룬¼ÓÔØʱҲ²»»áÓÉÈκδíÎóÌáʾ¡£