Kernel Module Programming Guide
¸®´ª½º Ä¿³Î ¸ðµâ ÇÁ·Î±×·¡¹Ö °¡À̵å
Peter Jay Salzman
Ori Pomerantz
Copyright © 2001 Peter Jay Salzman
2003-04-04 ver 2.4.0
¹ø¿ª ¿îÇü cloudshape (at) hanafos.com
2003-07-11 ver 2.4.0-trans-0.1
Contents
1.1. °¨»ç¸» ¶Ori Pomerantz´Â Yoav WeissÀÇ ¸¹Àº Á¶¾ð°ú ¹®¼ °ø°³Àü¿¡ ¹®¼¿¡¼ À߸øµÈ ºÎºÐµéÀ» ã¾Æ ÁØ °Í¿¡ °¨»çÀÇ ¸»À» ÀüÇÑ´Ù. ¶ÇÇÑ ³×´ú¶õµåÀÇ Frodo Looijaard, ´ºÁú·£µåÀÇ Stehpen Judd, ½º¿þµ§ÀÇ Ahltorp, ±×¸®°í ij³ª´Ù Äùº¤ÀÇ Emmanuel Papirakis¿¡°Ôµµ °¨»çÇÑ´Ù.
³»°¡ ÀÌ ¹®¼¸¦ °ü¸®ÇÒ ¼ö ÀÖµµ·Ï ÇØÁØ Á¡¿¡ ´ëÇØ Ori Pomerantz¿¡°Ô °¨»çÇÑ´Ù. ±×¿¡°Ô ÀÖ¾î ÀÌ°ÍÀº »ó´çÇÑ ³ë·ÂÀ̾ú´Ù. ³»°¡ ÀÌ ¹®¼¿¡ ÀÛ¾÷ÇÑ °ÍÀ» ±×°¡ ÁÁ¾ÆÇÏ±æ ¹Ù¶õ´Ù.
³ª¸¦ ÁöµµÇØÁØ Jeff Newmiller¿Í Rhonda Bailey¿¡°Ôµµ °¨»çÇÑ´Ù. ±×µéÀÌ ¹Ù»Ý¿¡µµ ºÒ±¸ÇÏ°í Àγ»½ÉÀ» °¡Áö°í ³ª¿¡°Ô ±×µéÀÇ °æÇèÀ» ÀüÇØ ÁÖ¾ú´Ù. David Porter´Â LaTeX ¼Ò½º¸¦ DocBookÀ¸·Î ÄÁ¹öÆÃÇÏ´Â Áö·çÇÏ°í °ñÄ¡ ¾ÆÇ Á÷¾÷À» °¡Áö°í ÀÖÁö¸¸ ´©±º°¡´Â ±× ÀÏÀ» Çؾ߸¸ ÇÑ´Ù. David¿¡°Ôµµ °¨»çÇÑ´Ù.
http://www.tldp.org/LDP/lkmpg/www.kernelnewbies.org ÀÇ »ç¶÷µé¿¡°Ôµµ °¨»ç¸¦ ÇÑ´Ù. ƯÈ÷, kernelnewbies.org¿¡ µå³ªµé¸ç Ãʺ¸µé °¡¸£Ä¡´Â °Í ¿Ü¿¡µµ ÇÒ ÀÏÀÌ ¹«Ã´ ¸¹À» °ÍÀÓÀÌ ºÐ¸íÇÑ Mark McLoughlin°ú John Levon¿¡°Ô °¨»ç¸¦ º¸³½´Ù. If this guide teaches you anything, they are partially to blame. ¸¸¾à ÀÌ ¹®¼°¡ ´ç½Å¿¡°Ô º° Àǹ̰¡ ¾ø´Ù¸é ±×µé¿¡°Ôµµ Ã¥ÀÓÀÌ ÀÖ´Ù(¿ªÁÖ: ±×¸¸Å ±×µéÀÇ ¿ªÇÒÀÌ Áß¿äÇßÀ½ ).
Ori¿Í ³ª´Â Richard M. Stallman°ú Linus Tovalds¿¡°Ô ¼º´É ÁÁÀº OS¸¦ »ç¿ëÇÏ°Ô ÇØÁØ °Í°ú ±×°ÍÀÌ ¾î¶»°Ô ÀÛµ¿ÇÏ´ÂÁö ÀÚ¼¼È÷ ¾Ë ¼ö ÀÖ´Â ±âȸ¸¦ ÁØ Á¡¿¡ ´ëÇØ °¨»çÇÑ´Ù. ³ª´Â Linus¸¦ ¸¸³ Àûµµ ¾ø°í, ¾ÕÀ¸·Îµµ ¸ø ¸¸³ª°ÚÁö¸¸, ±×´Â ³ªÀÇ Àλý¿¡ »ó´çÇÑ º¯È¸¦ ÁÖ¾ú´Ù.
´ÙÀ½Àº ³ª¿¡°Ô ÁÁÀº Á¦¾ÈÀ» Çϰųª ¿À·ù¼öÁ¤ÀÇ ¸Þ½ÃÁö¸¦ º¸³½ »ç¶÷µéÀÌ´Ù. Ignacio Martin and David Porter
1.2. Nota Bene ¶Ori's original document was good about supporting earlier versions of Linux, going all the way back to the 2.0 days. I had originally intended to keep with the program, but after thinking about it, opted out. My main reason to keep with the compatibility was for Linux distributions like LEAF, which tended to use older kernels. However, even LEAF uses 2.2 and 2.4 kernels these days.
Both Ori and I use the x86 platform. For the most part, the source code and discussions should apply to other architectures, but I can't promise anything. One exception is Chapter 12, Interrupt Handlers, which should not work on any architecture except for x86.
2.1. Ä¿³Î ¸ðµâÀ̶õ ¶´ç½ÅÀº Ä¿³Î ¸ðµâÀ» ÀÛ¼ºÇÏ·Á°í ÇÑ´Ù. C¸¦ ¾Ë°í ÇÁ·Î¼¼½º·Î ÀÛµ¿ÇÏ´Â ÀϹÝÀûÀÎ ÇÁ·Î±×·¥À» ÀÛ¼ºÇØ ºÃ°í ÀÌÁ¦´Â ¾îµð¼ ½ÇÁúÀûÀÎ ÀÛ¾÷ÀÌ ÇàÇØÁö´ÂÁö, ÇϳªÀÇ ¿ÍÀϵå Æ÷ÀÎÅÍ°¡ ÆÄÀÏ ½Ã½ºÅÛÀ» ¿ÏÀüÈ÷ Áö¿ï ¼ö ÀÖ°í ÄÚ¾î ´ýÇÁ°¡ ½Ã½ºÅÛÀÇ ¸®ºÎÆÃÀ» ÀǹÌÇÑ´Ù´Â °ÍÀ» ¾Ë°í ÀÖ´Ù.
Ä¿³Î ¸ðµâÀ̶õ Á¤È®È÷ ¹«¾ùÀΰ¡? ¸ðµâÀ̶õ ¿ä±¸¿¡ µû¶ó Ä¿³Î¿¡ ÀûÀç µÇ°Å³ª ÇØÁ¦ µÉ ¼ö ÀÖ´Â ÄÚµå´Ù. ½Ã½ºÅÛÀÇ Àç°¡µ¿ ¾øÀÌ Ä¿³ÎÀÇ ±â´ÉÀ» È®ÀåÀ» °¡´ÉÄÉÇÏ´Â °ÍÀÌ´Ù. ¿¹·Î ¸ðµâÀÇ ÇÑ Á¾·ù´Â µð¹ÙÀ̽º µå¶óÀ̹ö´Ù. ±×¸®°í ±×°ÍÀº ½Ã½ºÅÛ¿¡ ¿¬°áµÈ Çϵå¿þ¾î¿¡ Ä¿³ÎÀÌ Á¢±ÙÇÒ ¼ö ÀÖµµ·Ï ÇØ ÁØ´Ù. ¸ðµâÀÌ ¾ø´Ù¸é ¿ì¸®´Â ¸ð³î¸®Æ½ Ä¿³ÎÀ» ´Ù½Ã ºôµå ÇØ¾ß Çϸç, Ä¿³Î À̹ÌÁö¿¡ »õ·Î¿î ±â´ÉÀ» Á÷Á¢ÀûÀ¸·Î Ãß°¡ ½ÃÄÑ¾ß ÇÑ´Ù. ´ë±Ô¸ð Ä¿³Î¿¡¼´Â, ¿ì¸®°¡ ¿øÇÏ´Â »õ·Î¿î ±â´ÉÀ» Ãß°¡ Çϱâ À§Çؼ ¸Å¹ø Ä¿³ÎÀ» ´Ù½Ã ºôµåÇØ¾ß ÇÏ°í, ´Ù½Ã ºÎÆÃÇؾßÇÏ´Â ´ÜÁ¡À» °®°Ô µÈ´Ù.
2.2. ¾î¶»°Ô ¸ðµâÀ» Ä¿³Î¿¡ ³ÖÀ» °ÍÀΰ¡? ¶lsmod¸¦ ½ÇÇàÇÔÀ¸·Î½á ´ç½ÅÀº ÀÌ¹Ì Ä¿³Î¿¡ ÀûÀçµÇÀÖ´Â ¸ðµâÀ» º¼ ¼ö ÀÖÀ¸¸ç, lsmod´Â /proc/modules ÆÄÀÏÀ» Àоî Á¤º¸¸¦ ¾ò¾î ¿Â´Ù.
¸ðµâÀº Ä¿³Î¿¡¼ ¾î¶»°Ô ÀÚ½ÅÀÇ À§Ä¡¸¦ ã¾Æ³¾±î? Ä¿³Î ³»ºÎ¿¡ Á¸ÀçÇÏÁö ¾Ê´Â Ư¡À» Ä¿³ÎÀÌ ¾Ë ÇÊ¿ä°¡ ÀÖÀ» ¶§, Ä¿³Î ¸ðµâ µ¥¸óÀÎ kmod(ÀÌÀü ¹öÀüÀÇ ¸®´ª½º¿¡¼´Â kerneld·Î ¾Ë·ÁÁ® ÀÖ´Ù.) ¸ðµâÀ» ·Îµå ½ÃÅ°±â À§ÇØ modprobe¸¦ ½ÇÇà ½ÃŲ´Ù. modprobe¿¡ ´ÙÀ½ÀÇ µÎ ÇüÅ·Π¹®ÀÚ¿ÀÌ Àü´ÞµÈ´Ù.
alias char-major-10-30 softdogÀϹÝÀûÀÎ ¾ÆÀ̵§Æ¼ÆÄÀ̾î´Â softdog.o¶ó´Â ¸ðµâÀ» ÂüÁ¶ÇÑ´Ù´Â »ç½ÇÀ» ¾Ë°Ô µÈ´Ù. ´ÙÀ½À¸·Î modprobe´Â /lib/modules/version/modules.dep ÆÄÀÏÀ» Á¶»çÇؼ ´Ù¸¥ ¸ðµâÀÌ ¿ä±¸µÇ´Â ¸ðµâÀÌ ÀûÀçµÇ±â Àü¿¡ ¸ÕÀú ÀûÀçµÇ¾ß Çϴ°¡¸¦ º»´Ù. ÀÌ ÆÄÀÏÀº depmod -a ¿¡ ÀÇÇØ »ý¼ºµÇ¸ç, ¸ðµâÀÇ ÀÇÁ¸¼ºÀ» ´ã°í ÀÖ´Ù. ¿¹¸¦ µé¾î msdos.o´Â fat.o¸ðµâÀÌ ¸ÕÀú Ä¿³Î¿¡ ÀûÀçµÈ »óŸ¦ ¿ä±¸ÇÑ´Ù. ¿äûµÈ ¸ðµâÀÌ »ç¿ëÇÏ´Â ½Éº¼(º¯¼ö³ª ÇÔ¼ö)À» ´Ù¸¥ ¸ðµâÀÌ Á¤ÀÇ Çߴ°¡¶ó´Â, ´Ù¸¥ ¸ðµâ¿¡ ´ëÇÑ ÀÇÁ¸¼ºÀ» °®´Â´Ù.
¸¶Áö¸·À¸·Î modprobe´Â ¼±Çà ¸ðµâÀ» Ä¿³Î¿¡ ÀûÀçÇϱâ À§ÇØ insmod¸¦ »ç¿ëÇÏ°í, ¿ä±¸µÈ ¸ðµâÀ» ÀûÀçÇÑ´Ù. modprobe´Â insmod¿¡ Ç¥ÁØ ¸ðµâ µð·ºÅ丮ÀÎ /lib/modules/version/À» »ç¿ëÇϵµ·Ï Áö½ÃÇÑ´Ù. insmod´Â ¸ðµâÀÇ À§Ä¡¿¡ ´ëÇÑ Á¤º¸¸¦ ÀüÇô ¸ð¸£°Ô µÇÀÖ´Ù. ¹Ý¸é¿¡ modprobe´Â ¸ðµâÀÇ ±âº» À§Ä¡¸¦ ¾Ë°í ÀÖ´Ù. ¿¹¸¦ µé¾î msdos¸ðµâÀ» ÀûÀçÇϱ⠿øÇÑ´Ù¸é ´ÙÀ½ÀÇ µÎ °¡Áö¸¦ ½ÇÇàÇØ¾ß ÇÑ´Ù.
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"¸¦ ½ÇÇàÇÏÀÚ.
¸®´ª½º´Â modprobe, insmode, 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 ¸ðµâ¿¡ ´ëÇÑ °æ·Î¸¦ ã¾Æ ´ëüÇϵµ·Ï ÇÑ´Ù. º¸µíÀÌ, ½© ¸ÞŸ ij¸¯ÅÍ°¡ »ç¿ë °¡´ÉÇÏ´Ù.
path[net] ÇàÀº modprobe·Î ÇÏ¿©±Ý net ¸ðµâÀ» ~p/modules/ µð·ºÅ丮¿¡¼ ãµµ·Ï ÇÑ´Ù. ±×·¯³ª pathnet¿¡ ¹Ù·Î ¼±ÇàµÇ´Â ¡°keep¡±Àº modprobe¿¡°Ô misc¸ðµâ¿¡¼ ÇÑ °Íó·³ Ç¥ÁØ °Ë»ö °æ·Î¸¦ ´ëüÇÏÁö ¾Ê°í, ÇØ´ç µð·ºÅ丮¸¦ net¸ðµâÀ» ãÀ» ¶§ Ç¥ÁØ °Ë»ö °æ·Î·Î Ãß°¡Çϵµ·Ï ÇÑ´Ù.
kmod°¡ ÀϹÝÀûÀÎ ¾ÆÀ̵§Æ¼ÆÄÀ̾îÀÎ ¡®eth0¡¯¸¦ ÀûÀçÇ϶ó´Â ¿ä±¸ÇÒ ¶§¸¶´Ù, eepro.o¸¦ ÀûÀçÇ϶ó°í ÇÑ´Ù.
/etc/modules.conf ¿¡¼ "alias block-major-2 floppy"°°Àº ÇàÀº ¹ß°ßÇÏÁö ¸øÇÒ °ÍÀÌ´Ù. ¿Ö³ÄÇá¸é, modprobe´Â ´ëºÎºÐÀÇ ½Ã½ºÅÛ¿¡¼ »ç¿ëµÇ´Â Ç¥ÁØ µå¶óÀ̹öµé¿¡ ´ëÇØ ¾Ë°í Àֱ⠶§¹®ÀÌ´Ù.
ÀÌÁ¦ ¸ðµâÀÌ ¾î¶»°Ô Ä¿³Î¿¡ ÀûÀçµÇ´ÂÁö ¾Ë¾ÒÀ» °ÍÀÌ´Ù. ¡®stacking modules¡¯¶ó°í ºÎ¸£´Â ¸ðµâ¿¡ ÀÇÁ¸ÀûÀÎ ¸ðµâÀ» ÀÛ¼ºÇÑ´Ù¸é ¸î °¡Áö ´õ ¾ð±ÞÇÒ °ÍµéÀÌ ÀÖ´Ù. ÀÌ°ÍÀº ´ÙÀ½À¸·Î ¹Ì·é´Ù. »ó´ëÀûÀ¸·Î °í ³ÀÌÀÇ ÀïÁ¡À» ´Ù·ç±â Àü¿¡ ´Ù·ï¾ß ÇÒ ºÎºÐÀÌ ¸¹ÀÌ ÀÖ´Ù.
2.2.1. ½ÃÀÛÇϱâ Àü¿¡ ¶Äڵ带 ÆÄÇìÄ¡±â Àü¿¡ ¿ì¸®°¡ ´Ù·ï¾ßÇÒ ¸î¸î ÁÖÁ¦°¡ ´õ ÀÖ´Ù. ¸ðµç »ç¶÷ÀÇ ½Ã½ºÅÛÀÌ »óÀÌÇÏ°í ±×µé¸¸ÀÇ °ü½ÀÀÌ ÀÖ´Ù. ¡°hello world¡± ÇÁ·Î±×·¥À» ÄÄÆÄÀÏÇÏ°í ¿Ã¹Ù¸£°Ô ÀûÀçÇÏ´Â °ÍÀº ¶§·Ð trick(?)Àϼö ÀÖ´Ù. óÀ½ ¸î¸î Àå¾Ö¸¦ ±Øº¹ÇÏ°í ³ª¸é, ¼ødz¿¡ µÀÀ» ´Ü µí ÁøÇàµÉ °ÍÀ̶ó »ý°¢ÇÑ´Ù.
2.2.1.1. ¸ðµâ ¹öÀü ¶CONFIG_MODVERSIONS¸¦ Ä¿³Î¿¡¼ È°¼ºÈ ½ÃÅ°Áö ¾Ê¾Ò´Ù¸é, ƯÁ¤ Ä¿³Î¿¡¼ ÄÄÆÄÀÏÇÑ ¸ðµâÀº ´Ù¸¥ Ä¿³Î·Î ºÎÆÃÇÑ ½Ã½ºÅÛ¿¡´Â ÀûÀç µÇÁö ¾Ê´Â´Ù. À̹®¼ ÈĹݺΠ±îÁö´Â ¸ðµâ ¹öÀü¿¡ °üÇÑ ¹®Á¦¸¦ ´Ù·çÁö ¾ÊÀ» °ÍÀÌ´Ù. ÀÌ ¹®¼ÀÇ ¿¹Á¦´Â modversioning±â´ÉÀ» È°¼ºÈÇÑ Ä¿³ÎÀ» »ç¿ëÇÑ´Ù¸é ÀÛµ¿ÇÏÁö ¾ÊÀ» °ÍÀÌ´Ù. ´ëºÎºÐÀÇ ¹èÆ÷ÆÇ Ä¿³ÎÀº ÀÌ ±â´ÉÀ» È°¼ºÈ ½ÃŲ »óÅ·Π³ª¿Â´Ù. ¸¸¾à ¸ðµâÀ» ÀûÀçÇÒ ¶§ ¹öÀü ¹®Á¦·Î ¿¡·¯°¡ ³´Ù¸é modversioning ±â´ÉÀ» ºñÈ°¼ºÈ ½ÃŲ ÈÄ Ä¿³ÎÀ» ´Ù½Ã ÄÄÆÄÀÏ ÇØ¾ß ÇÒ °ÍÀÌ´Ù.
2.2.1.2. X »ç¿ëÇϱ⠶ÀÌ ¹®¼¿¡ ³ª¿Â ¸ðµç ¿¹Á¦¸¦ ŸÀÌÇÎÇÏ°í ÄÄÆÄÀÏÇÏ°í ÀûÀçÇغ¸±â¸¦ °·ÂÈ÷ ±ÇÇÏ´Ù. console¿¡¼ ÀÛ¾÷Çϱ⠿ª½Ã ±ÇÇÑ´Ù. X ȯ°æ¿¡¼ÀÇ ÀÛ¾÷À» ÇÏÁö ¸¶¶ó.
¸ðµâÀº printf()ó·³ ȸ鿡 Ãâ·ÂÀ» ÇÏÁö ¸øÇÏ°í ·Î±× Á¤º¸¿Í °æ°íµéÀ» Äַܼθ¸ Ãâ·ÂÇÑ´Ù. ¸¸ÀÏ xterm¿¡¼ ¸ðµâÀ» ÀûÀçÇÑ´Ù¸é, Á¤º¸¿Í °æ°íµéÀº ´ç½ÅÀÇ ·Î±× ÆÄÀÏ¿¡¸¸ ±â·ÏµÉ °ÍÀÌ´Ù. ·Î±× ÆÄÀÏÀ» È®ÀÎ Çϱâ Àü±îÁö´Â ±×°ÍÀ» º¸Áö ¸øÇÒ °ÍÀÌ´Ù. Áï°¢ÀûÀÎ Á¤º¸¸¦ À§Çؼ ¸ðµç ÀÛ¾÷À» Äֿܼ¡¼ Ç϶ó.
2.2.1.3. ÄÄÆÄÀÏ ¹®Á¦¿Í Ä¿³Î ¹öÀü ¶Á¾Á¾ ¸®´ª½º´Â Ç¥ÁØÀÌ ¾Æ´Ñ ¹æ½ÄÀ¸·Î ´Ù¾çÇÏ°Ô ÆÐÄ¡µÇ¼ ¹èÆ÷µÇ°í ±×°ÍÀº ¹®Á¦¸¦ ¾ß±âÇÑ´Ù.
´õ ÈçÇÑ ¹®Á¦´Â ¸î¸î ¹èÆǵéÀÌ ºÒ¿ÏÀüÇÑ Ä¿³Î Çì´õ¸¦ °¡Áö°í ¹èÆ÷µÈ´Ù´Â Á¡ÀÌ´Ù. ´ç½ÅÀÇ Äڵ带 ÄÄÆÄÀÏ ÇÒ ¶§ ¸®´ª½º Ä¿³ÎÀÇ ´Ù¾çÇÑ Çì´õ ÆÄÀÏÀ» »ç¿ëÇؼ ÄÄÆÄÀÏ ÇØ¾ß ÇÒ °ÍÀÌ´Ù. ¸ÓÇÇÀÇ ¹ýÄ¢Àº ¸ðµâÀÌ ÀÛµ¿Çϱ⿡ ÇÊ¿äÇÑ Çì´õ¸¸ ºüÁ®ÀÖ´Ù°í ¸»ÇÑ´Ù.(½ä·· Á¶Å©-_-¡° – ÇÊÀÚ°¡ ¾´°ÍÀÓ)
ÀÌ·± ¹®Á¦¸¦ ÇÇÇϱâ À§Çؼ´Â ¸®´ª½º Ä¿³Î ¹Ì·¯ »çÀÌÆ®¿¡¼ ´Ù¿î ¹Þ¾Æ ÄÄÆÄÀÏÇÏ°í ºÎÆýÃÄÑ ½Ã½ºÅÛÀ» »ç¿ëÇÒ °ÍÀ» °·ÂÈ÷ ±ÇÇÑ´Ù. ÀÚ¼¼ÇÑ »çÇ×Àº Linux Kernel HOWTO¸¦ Âü°íÇϱ⠹ٶõ´Ù.
¿ª¼³ÀûÀÌÁö¸¸ ÀÌ°Í ¿ª½Ã ¹®Á¦¸¦ ¸¸µç´Ù. ±âº»ÀûÀ¸·Î, ´ç½ÅÀÇ ½Ã½ºÅÛ¿¡ ÀÖ´Â GCC´Â ´ç½ÅÀÌ ¼³Ä¡ÇÑ ¹öÀüÀÇ Ä¿³Î Çì´õÆÄÀÏÀ» ã´Â °ÍÀÌ ¾Æ´Ï°í ±âº»À¸·Î ¼³Ä¡µÆ´ø Ä¿³Î Çì´õ(º¸Åë /usr/src/)¸¦ ãÀ» °ÍÀÌ´Ù. ÀÌ°ÍÀº gccÀÇ -l ¿É¼ÇÀ» »ç¿ëÇؼ ¼öÁ¤ÇÒ ¼ö ÀÖ´Ù.
3.1. Hello, World (part 1): The Simplest Module ¶¿ø½Ã ÇÁ·Î±×·¡¸Ó°¡ óÀ½À¸·Î ¿ø½Ã ÄÄÇ»ÅÍ¿¡ ù ÇÁ·Î±×·¥À» »õ°Ü ³Ö¾úÀ» ¶§, ±×°ÍÀº ¡®Hello World¡¯¶ó´Â ¹®ÀÚ¸¦ ¾ç¶¼ ±×¸²¿¡ »õ°Ü ³ÖÀº ÇÁ·Î±×·¥À̾ú´Ù. ·Î¸¶ÀÇ ÇÁ·Î±×·¥ Ã¥Àº ¡®Salut Mundi¡¯(hello worldÀÇ ·Î¸¶¾îÀÎ µí.. J)·Î ½ÃÀÛÇÑ´Ù. ÀÌ·± °ü½ÀÀ» ±ú¶ß¸° »ç¶÷¿¡°Ô ¾î¶² ÀÏÀÌ ÀϾ´ÂÁö ÀßÀº ¸ð¸£Áö¸¸, º°·Î ½Å°æ ¾²Áö ¾Ê¾Æµµ µÉ µí ÇÏ´Ù. Ä¿³Î ¸ðµâÀ» ÀÛ¼ºÇÏ´Â ±âº»ÀÌ µÇ´Â ´Ù¸¥ Ãø¸é¿¡¼ÀÇ ¿¹·Î Hello World·ùÀÇ ÇÁ·Î±×·¥À» °¡Áö°í ½ÃÀÛÇغ¸ÀÚ.(¾î»öÇÑ ¹ø¿ª...)
´ÙÀ½Àº °¡Àå °£´ÜÇÑ ¸ðµâÀÌ´Ù. ¾ÆÁ÷ ÄÄÆÄÀÏÇÏÁö ¸»ÀÚ; ´ÙÀ½ Àå¿¡¼ ¸ðµâÀ» ÄÄÆÄÀÏÇÏ´Â °Í¿¡ ´ëÇØ ´Ù·ê °ÍÀÌ´Ù.
Example 2-1. hello-1.c
/* hello-1.c - The simplest kernel module. */
#include <linux/module.h> /* ¸ðµç ¸ðµâ¿¡ ÇÊ¿ä */ #include <linux/kernel.h> /* KERN_ALERT¿¡ ÇÊ¿ä */ int init_module(void) { printk("<1>Hello world 1.\n"); // 0ÀÌ ¾Æ´Ñ °ªÀ» ¸®ÅÏÇÏ´Â °ÍÀº init_moduleÀÌ ½ÇÆÐÇÑ °ÍÀ» ÀǹÌÇÑ´Ù. °í·Î ¸ðµâÀº ·ÎµåµÇÁö ¸øÇÑ´Ù. return 0; } void cleanup_module(void) { printk(KERN_ALERT "Goodbye world 1.\n"); } Ä¿³Î ¸ðµâÀº ÃÖ¼Ò µÎ °³ÀÇ ÇÔ¼ö¸¦ Æ÷ÇÔÇØ¾ß ÇÑ´Ù: ¸ðµâÀÌ Ä¿³Î¿¡ ÀûÀçµÉ ¶§ È£ÃâµÇ´Â ½ÃÀÛ(ÃʱâÈ) ÇÔ¼öÀÎ init_module() ±×¸®°í ¸ðµâÀÌ ÇØÁ¦µÇ±â Á÷Àü¿¡(rmmod) È£ÃâµÇ´Â Á¾·á(ÇØÁ¦) ÇÔ¼öÀÎ cleanup_module()ÀÌ ¹Ù·Î ±×°ÍÀÌ´Ù. ½ÇÁ¦, Ä¿³Î 2.3.13ºÎÅÍ ÀÌ·± ºÎºÐ¿¡ ¸¹Àº º¯È°¡ ÀÖ¾ú´Ù. ´ç½ÅÀº ½ÃÀÛÇϰųª Á¾·áÇÒ ¶§ ¸¶À½¿¡ µå´Â °ÍÀ» »ç¿ëÇÒ ¼ö ÀÖÀ¸¸ç, ÀÌ·± °ÍµéÀ» Section 2.3¿¡¼ ¹è¿ï °ÍÀÌ´Ù. »ç½Ç »õ·Î¿î ¹æ½ÄÀÌ ´õ ³´´Ù. ±×·¯³ª ¸¹Àº »ç¶÷µéÀÌ ¿©ÀüÈ÷ ½ÃÀÛ°ú ³¡¿¡ init_module() °ú cleanup_module()ÇÔ¼ö¸¦ »ç¿ëÇÑ´Ù.
ÀüÇüÀûÀ¸·Î init_module()ÇÔ¼ö´Â Ä¿³Î¿¡ ¾î¶² Çîµé·¯¸¦ µî·ÏÇϰųª, Ä¿³ÎÀÌ °¡Áö°í ÀÖ´Â ÇÔ¼öÀÇ Äڵ带 ´ëüÇÑ´Ù. ÀϹÝÀûÀ¸·Î ƯÁ¤ÇÑ ÀÛ¾÷À» ¼öÇàÇÑ ÈÄ, ¿ø·¡ÀÇ ÇÔ¼ö¸¦ ´Ù½Ã È£ÃâÇÑ´Ù.). cleanup_module()ÇÔ¼ö´Â init_module()ÇÔ¼ö°¡ ÇàÇÑ °ÍÀ» º¹±Í½ÃÄÑ ¸ðµâÀ» ¾ÈÀüÇÏ°Ô ÇØÁ¦(unload)ÇÒ ¼ö ÀÖ°Ô ÇÑ´Ù.
¸¶Áö¸·À¸·Î ¸ðµç Ä¿³Î ¸ðµâÀº linux/module.h¸¦ Æ÷ÇÔÇØ¾ß ÇÑ´Ù. linux/kernel.h´Â printk()ÇÔ¼öÀÇ log levelÀÎ KERN_ALERT¸¦ À§Çؼ¸¸ ¿©±â¼ ÇÊ¿äÇϸç ÀÌ·± ³»¿ëÀº printk()ÇÔ¼ö ¼Ò°³¿¡¼ ¹è¿ï °ÍÀÌ´Ù.
3.1.1. printk()ÇÔ¼ö ¼Ò°³ ¶´ç½ÅÀÇ »ý°¢°ú ´Ù¸£°Ô printk()´Â »ç¿ëÀÚ¿Í Á¤º¸ ±³È¯À» À§ÇÑ °ÍÀº ¾Æ´Ï´Ù.(¿ì¸®°¡ ÀÌ·± ¸ñÀûÀ¸·Î hello-1¿¡¼ printk()¸¦ »ç¿ëÇÒ Áö¶óµµ) ÀÌ°ÍÀº Ä¿³Î¿¡ ±â·Ï(logging)ÇÏ´Â ¹æ½ÄÀ̸ç, °æ°í¸¦ Çϰųª Á¤º¸¸¦ ³²±â±â À§ÇØ »ç¿ëµÈ´Ù. °¢°¢ÀÇ printk()´Â ¿ì¼± ¼øÀ§¸¦ °¡Áö°í »ç¿ëµÇ¸ç, /which is the <1> and KERN_ALERT you see /ÀÌ°ÍÀº <1> ȤÀº KERN_ALERT ¿Í °°Àº ÇüÅ·Π»ç¿ëµÈ´Ù. 8°³ÀÇ ¿ì¼±¼øÀ§°¡ ÀÖÀ¸¸ç, Ä¿³ÎÀº ±×¿¡ »óÀÀÇÏ´Â ¸ÅÅ©·Î¸¦ °¡Áö°í ÀÖ¾î ÀÌÇØÇϱ⠾î·Á¿î ¹øÈ£¸¦ »ç¿ëÇÒ ÇÊ¿ä°¡ ¾ø´Ù. À̵éÀº linux/kernel.h¿¡¼ ã¾Æº¼ ¼ö ÀÖ´Ù. ¿ì¼± ¼øÀ§¸¦ Á¤ÇÏÁö ¾Ê°í »ç¿ëÇÑ´Ù¸é ±âº»ÀûÀÎ ¿ì¼±¼øÀ§ÀÎ DEFAULT_MESSAGE_LOGLEVELÀÌ »ç¿ëµÉ °ÍÀÌ´Ù.
¿ì¼± ¼øÀ§ ¸ÅÅ©·Î¸¦ Àб⸦ ±ÇÇÑ´Ù. Çì´õ ÆÄÀÏÀº °¢ ¿ì¼± ¼øÀ§°¡ ÀǹÌÇÏ´Â ¹Ùµµ ¼³¸íÇØ ÁØ´Ù. ½ÇÁ¦ <4>¿Í °°Àº ¹øÈ£´Â ¾²ÀÌÁö ¾ÊÀ¸¸ç ´ë½Å KERN_WARNNING°ú °°Àº ¸ÅÅ©·Î¸¦ »ç¿ëÇÑ´Ù.
¸¸¾à int console_loglevelº¸´Ù ¿ì¼± ¼øÀ§°¡ ³·À¸¸é, ÇØ´ç ¸Þ½ÃÁö´Â ´ç½ÅÀÇ ÇöÀç Å͹̳ο¡ º¸¿©Áú °ÍÀÌ´Ù. syslogd¿Í klogd°¡ ½ÇÇà ÁßÀ̶ó¸é ¸ÞÁö½Ã°¡ ÄַܼΠÃâ·Â¿©ºÎ¿Í °ü°è ¾øÀÌ /var/log/messages¿¡ Ãß°¡µÈ´Ù. printk()ÀÇ ¸Þ½ÃÁö°¡ ·Î±× ÆÄÀÏ¿¡¸¸ ³²°ÜÁöÁö ¾Ê°í ÄַܼΠ¹Ýµå½Ã Ãâ·ÂµÇµµ·Ï Çϱâ À§ÇØ KERN_ALERT¿Í °°ÀÌ ³ôÀº ¿ì¼±¼øÀ§¸¦ »ç¿ëÇÑ´Ù. ½ÇÁ¦ ¸ðµâÀ» ÀÛ¼ºÇÒ ¶§ ÀûÀýÈ÷ »óȲ¿¡ ¸Â´Â ¿ì¼±¼øÀ§¸¦ »ç¿ëÇϱ⠿øÇÒ °ÍÀÌ´Ù.
3.2. Ä¿³Î ¸ðµâ ÄÄÆÄÀÏ ¶Ä¿³Î ¸ðµâÀº Àç´ë·Î ÀÛµ¿Çϱâ À§Çؼ GCCÀÇ Æ¯Á¤ÇÑ ¿É¼Ç°ú ÇÔ²² ÄÄÆÄÀÏ µÇ¾ß ÇÑ´Ù. Á¤ÀÇµÈ Æ¯Á¤ÇÑ ½Éº¼°ú ÇÔ²² ÄÄÆÄÀÏ µÉ ÇÊ¿äµµ ÀÖ´Ù. ½ÇÇà ÆÄÀÏÀ» ÄÄÆÄÀÏÇÏ´ÂÁö Ä¿³Î ¸ðµâÀ» ÄÄÆÄÀÏÇÏ´ÂÁö¿¡ µû¶ó Ä¿³Î Çì´õ ÆÄÀÏÀÌ ´Ù¸£°Ô µ¿ÀÛÇØ¾ß Çϱ⠴빮ÀÌ´Ù. GCCÀÇ –D¿É¼ÇÀ» »ç¿ëÇϰųª #define ÇÁ¸®ÇÁ·Î¼¼¼ ¸í·ÉÀ» »ç¿ëÇØ ½Éº¼À» Á¤ÀÇÇÒ ¼ö ÀÖ´Ù. ÀÌ Àå¿¡¼ Ä¿³Î ¸ðµâÀ» ÄÄÆÄÀÏÇϱâ À§ÇØ ÇÊ¿äÇÑ °ÍµéÀ» ¸ðµÎ ´Ù·é´Ù.
hello-1.c ¸ðµâ ÄÄÆÄÀÏÀ» À§ÇÑ MakefileÀ» »ìÆ캸ÀÚ
Example 2-2. Makefile for a basic kernel module
TARGET := hello-1
WARN := -W -Wall -Wstrict-prototypes -Wmissing-prototypes INCLUDE := -isystem /lib/modules/`uname -r`/build/include CFLAGS := -O2 -DMODULE -D__KERNEL__ ${WARN} ${INCLUDE} CC := gcc-3.0 ${TARGET}.o: ${TARGET}.c .PHONY: clean clean: rm -rf {TARGET}.o ¿¬½ÀÀ¸·Î hello-1.c¸¦ ÄÄÆÄÀÏÇÏ°í insmod ./hello-1.o¸¦ Ä¿³Î¿¡ ¿Ã·Áº¸ÀÚ. ÀߵǴ°¡? Ä¿³Î¿¡ ÀûÀçµÈ ¸ðµç ¸ðµâÀº /proc/modules¿¡ ¸®½ºÆ®µÈ´Ù. ´ç½ÅÀÇ ¸ðµâÀÌ Ä¿³ÎÀÇ ÀϺΰ¡ µÆ´ÂÁö ¾Ë¾Æ º¸±â À§ÇØ ±× ÆÄÀÏÀ» Ãâ·ÂÇغ¸ÀÚ. ÃàÇÏÇÑ´Ù. ´ç½ÅÀº ¸®´ª½º Ä¿³ÎÄÚµåÀÇ ÀÛ¼ºÀÚ°¡ µÆ´Ù. Áñ°Å¿òÀº Àá½Ã ¹Ì·ïµÎ°í rmmod hello-1¸¦ »ç¿ëÇØ Ä¿³Î·ÎºÎÅÍ ´ç½ÅÀÇ ¸ðµâÀ» Á¦°Å ÇÏÀÚ. ´ç½ÅÀÇ ½Ã½ºÅÛ ·Î±×ÆÄÀÏ¿¡ ±â·ÏÀÌ µÆ´ÂÁö º¸±â À§ÇØ /var/log/messages ÆÄÀÏÀ» »ìÆì º¸ÀÚ.
µ¶ÀÚ¸¦ À§ÇÑ ¶Ç ´Ù¸¥ ¿¹Á¦°¡ ÀÖ´Ù. ¾Õ¼ ¾ð±ÞÇÑ init_module()ÇÔ¼öÀÇ ¸®ÅÏ °ªÀ» 0 ¾Æ´Ñ À½¼ö·Î º¯°æÇÑ ÈÄ ´Ù½Ã ÄÄÆÄÀÏ ÇÏ°í ·ÎµåÇØ º¸ÀÚ. ¾î¶² ÀÏÀÌ ÀϾ´Â°¡?
3.3. Hello World (part 2) ¶¿©·¯ºÐÀº ¿©·¯ºÐÀÇ init ¿Í cleanup ÇÔ¼ö À̸§À» ¹Ù²Ü ¼ö ÀÖ´Ù. ÀÌÈÄ·Î ±×µéÀÇ À̸§ÀÌ ¹Ýµå½Ã init_moduel(), cleanup_module()ÀÏ ÇÊ¿ä´Â ¾ø´Ù. ÀÌ´Â module_init()¿Í module_exit()¸ÅÅ©·Î¿¡ ÀÇÇØ ÀÌ·ïÁø´Ù. ÀÌ ¸ÅÅ©·Î´Â linux/init.h¿¡ ÀúÀÇ µÇÀÖ´Ù. ¼±ÇàµÇ¾ß ÇÒ °ÍÀº ¸ÅÅ©·Î¸¦ È£ÃâÇϱâ Àü¿¡ init¿Í cleanupÇÔ¼ö¶ó Á¤ÀÇ µÅÀÖ¾î¾ß ÇÑ´Ù °Í »Ó, ±×·¸Áö ¾Ê´Ù¸é ÄÄÆÄÀÏ ¿¡·¯¸¦ ¸¸³¯ °ÍÀÌ´Ù. ÀÌ·± Å×Å©´ÐÀÇ ¿¹°¡ ÀÖ´Ù.
Example 2-3. hello-2.c
/* hello-2.c - Demonstrating the module_init() and module_exit() macros.
This is the preferred over using init_module() and cleanup_module(). hello-2.c – module_init()¿Í module_exit()¸ÅÅ©·ÎÀÇ ¿¹. ÀÌ°ÍÀº init_module()°ú cleanup_moduel() º¸´Ù ³´´Ù. */ #include <linux/module.h> // Needed by all modules #include <linux/kernel.h> // Needed for KERN_ALERT#include <linux/init.h> // Needed for the macrosstatic int hello_2_init(void) { printk(KERN_ALERT "Hello, world 2\n"); return 0; } static void hello_2_exit(void) { printk(KERN_ALERT "Goodbye, world 2\n"); } module_init(hello_2_init); module_exit(hello_2_exit); ÀÌÁ¦ ¿ì¸®´Â µÎ°³ÀÇ ½ÇÁ¦ Ä¿³Î ¸ðµâÀ» üÇèÇß´Ù. »ý»ê¼ºÀ» ³ôÀ̱â À§ÇØ ¿ì¸®´Â MakefileÀ» È°¿ëÇØ¾ß ÇÑ´Ù. ´ÙÀ½Àº ¾Õ µÎ °³ÀÇ ¸ðµâÀ» ¸ðµÎ ÄÄÆÄÀÏ ÇÒ ¼ö ÀÖ´Â °³¼±µÈ Makefile ÀÌ´Ù. °£°á¼º, ±Ô¸ð¸é¿¡¼ ÃÖÀûÈµÈ °ÍÀÌ´Ù. ´ÙÀ½À» ÀÌÇØÇÒ ¼ö ¾ø´Ù¸é GNU Makefile¸Å´º¾ó ȤÀº, makefile infoÆäÀÌÁö¸¦ Àб⠹ٶõ´Ù.
Example 2-4. Makefile for both our modules
WARN := -W -Wall -Wstrict-prototypes -Wmissing-prototypes
INCLUDE := -isystem /lib/modules/`uname -r`/build/include CFLAGS := -O2 -DMODULE -D__KERNEL__ ${WARN} ${INCLUDE} CC := gcc-3.0 OBJS := ${patsubst %.c, %.o, ${wildcard *.c}} all: ${OBJS} .PHONY: clean clean: rm -rf *.o µ¶ÀÚµéÀ» À§ÇÑ ¿¹·Î, ¸¸¾à °°Àº µð·ºÅ丮¿¡ hello-3.c °°Àº ¸ðµâÀÌ Çϳª ´õ ÀÖ´Ù¸é ±× ¸ðµâÀ» ÀÚµ¿À¸·Î ÄÄÆÄÀÏ Çϱâ À§ÇØ ´ç½ÅÀº MakefileÀ» ¾î¶»°Ô ¼öÁ¤ÇÒ °ÍÀΰ¡?
3.4. Hello World (part 3): The __init and __exit Macros ¶´ÙÀ½Àº Ä¿³Î 2.2³ª ȤÀº ±× ÈÄ ¹öÀü¿¡¼ÀÇ ¿¹´Ù. init¿Í cleanup ÇÔ¼öÀÇ Á¤ÀÇ¿¡¼ÀÇ º¯È¸¦ ÁÖ¸ñÇ϶ó. ³»ÀåµÈ µå¶óÀ̹ö¿¡ ´ëÇØ initÇÔ¼ö°¡ ¼öÇàµÇ¸é, __init¸ÅÅ©·Î´Â initÇÔ¼ö°¡ ¹ö·ÁÁö°í(-_-¡°) ¸Þ¸ð¸®°¡ ¹ÝȯµÈ´Ù. ±×·¯³ª ¸ðµâÀº ÀûÀç ºÒ°¡´ÉÇÏ´Ù. ¾ðÁ¦ initÇÔ¼ö°¡ È£ÃâµÇ´Â °¡¸¦ »ý°¢ÇÑ´Ù¸é ÀÌ°ÍÀº ¿ÏÀüÈ÷ Ÿ´çÇÏ´Ù°í ´À³¥ °ÍÀÌ´Ù.
initÇÔ¼ö ÀÚü¿¡ ´ëÇÑ °ÍÀ̶ó±â º¸´Ù´Â initº¯¼ö¿¡ ´ëÇØ ÀÛ¿ëÇÏ´Â __init¿Í À¯»çÇÑ ¸ÅÅ©·ÎÀÎ __initdata¶ó´Â °Íµµ ÀÖ´Ù.
__exit¸ÅÅ©·Î´Â ¸ðµâÀÌ Ä¿³Î·Î ºôÆ®ÀÎ(¸ðµâ·Î ÄÄÆÄÀÏ ÇÏ´Â °ÍÀÌ ¾Æ´Ñ Ä¿³Î ÀϺηΠÄÄÆÄÀÏ ÇÏ´Â °Í)µÉ ¶§, ÇÔ¼öÀÇ È£ÃâÀ» »ý·«Çϸç __exitó·³ ÀûÀç °¡´ÉÇÑ ¸ðµâ¿¡ ¾î¶² ¿µÇâµµ ¹ÌÄ¡Áö ¾Ê´Â´Ù. ¸¶Âù°¡Áö·Î ¾ðÁ¦ cleanupÇÔ¼ö°¡ ÀÛµ¿ÇÏ´Â °í·ÁÇÑ´Ù¸é ÀÌÇØµÉ °ÍÀÌ´Ù. ³»ÀåµÈ µå¶óÀ̹ö´Â cleanupÇÔ¼ö°¡ ÇÊ¿ä ¾ø´Ù. ¹Ý¸é¿¡ ÀûÀç °¡´ÉÇÑ ¸ðµâÀº ÇÊ¿äÇÏ´Ù.
ÀÌ ¸ÅÅ©·ÎµéÀº 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 <linux/module.h> /* Needed by all modules */ #include <linux/kernel.h> /* Needed for KERN_ALERT */ #include <linux/init.h> /* Needed for the macros */ 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); ¸®´ª½º 2.2 Ä¿³ÎÀ» À§ÇÑ µå¶óÀ̹ö ¸ðµâ¿¡¼ __initfunction() °°Àº ÇÔ¼ö¸¦ º¸¾ÒÀ» °ÍÀÌ´Ù.
__initfunction(int init_module(void))
{ printk(KERN_ALERT "Hi there.\n"); return 0; } 3.5. Hello World (prt 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¿¡ Á¤ÀǵÇÀÖ°í ¹®¼È µÇ¾î ÀÖ´Ù.
ºñ½ÁÇÏ°Ô MOUDLE_DESCRIPTION() Àº ¸ðµâÀÌ ¹«¾ùÀ» Çϴ°¡¸¦ , MOUDLE_AUTHOR()Àº ¸ðµâÀÇ ÀúÀÚ¸¦ MODULE_SUPPORTED_DEVICE()´Â ¾î¶² ŸÀÔÀÇ ÀåÄ¡¸¦ ¸ðµâÀÌ Áö¿øÇÏ´Â °¡¸¦ ¾Ë·ÁÁØ´Ù.
ÀÌ·± ¸ÅÅ©·ÎµéÀº linux/module.h¿¡ Á¤ÀǵÇÀÖ°í Ä¿³Î ÀÚü¿¡¼´Â »ç¿ëµÇÁö ¾Ê´Â´Ù. À̰͵éÀº ¹®È¸¦ °£´ÜÈ÷ Çϸç, objdump¿Í °°Àº ÅøÀ» ÀÌ¿ëÇØ º¼ ¼ö ÀÖ´Ù. µ¶ÀÚµéÀÇ ¿¬½ÀÀ» À§ÇØ linux/drivers¿¡¼ ¾î¶»°Ô ¸ðµâ ÀúÀÚµéÀÌ ¸ðµâÀ» ¹®¼È Çϱâ À§ÇØ ÀÌ ¸ÅÅ©·ÎµéÀ» »ç¿ëÇߴ°¡ ã¾Æ º¸±æ ¹Ù¶õ´Ù.
Example 2-6. hello-4.c
/* hello-4.c - Demonstrates module documentation. */
#include <linux/module.h> #include <linux/kernel.h> #include <linux/init.h> #define DRIVER_AUTHOR "Peiter Jay Salzman <p@dirac.org>" #define DRIVER_DESC "A sample driver" int init_hello_3(void); void cleanup_hello_3(void); static int init_hello_4(void){ printk(KERN_ALERT "Hello, world 4\n"); return 0; } static void 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: */ MODULE_LICENSE("GPL"); // Get rid of taint message by declaring code as 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"); 3.6. Ä¿¸Çµå ¶óÀÎ ÀÎÀÚ ¸ðµâ¿¡ ³Ñ±â±â ¶¸ðµâÀº Ä¿¸Çµå¶óÀÎ ÀÎÀÚ¸¦ ¹ÞÀ» ¼ö ÀÖ´Ù. ±âÁ¸¿¡ »ç¿ëÇÏ´ø °Íó·³ argc/argv¸¦ °¡Áö°í ÇÒ ¼ö´Â ¾ø´Ù.
ÀÎÀÚ¸¦ ´ç½ÅÀÇ ¸ðµâ·Î ³Ñ±â±â À§Çؼ´Â Ä¿¸Çµå¶óÀÎ ÀÎÀÚÀÇ °ªÀ» ÀúÀåÇÒ º¯¼ö¸¦ Àü¿ªÀ¸·Î ¼±¾ðÇÑ ÈÄ ¸ÞÄ¿´ÏÁòÀ» È°¼ºÈ ½ÃÅ°±â À§ÇØ MODULE_PARAM()¸ÅÅ©·Î¸¦ »ç¿ëÇÑ´Ù. ½ÇÇà ½Ã°£¿¡ insmod´Â ÁÖ¾îÁø ÀÎÀÚ·Î º¯¼ö¸¦ ä¿ï °ÍÀÌ´Ù. º¯¼öÀÇ ¼±¾ð°ú ¸ÅÅ©·ÎµéÀº ¸íÈ®¼ºÀ» À§ÇØ ¸ðµâ ¼µÎ¿¡ À§Ä¡ÇØ¾ß ÇÑ´Ù. ´ÙÀ½ÀÇ ¿¹´Â ¾î´ÇÑ ³» ¼³¸íÀ» ¸í¹éÈ÷ ÇØÁØ´Ù.(³» ¹ø¿ªµµ ^^)
MODULE_PARAM() ¸ÅÅ©·Î´Â 2°³ÀÇ ÀÎÀÚ¸¦ ¹Þ´Â´Ù º¯¼öÀÇ À̸§°ú ŸÀÔ Áö¿øÇϴ ŸÀÔÀº 1byteÀΡ±b¡±, short intÀÎ ¡°h¡±, integerÀÎ ¡°i¡±, longÀÎ ¡°l¡±, stringÀÎ ¡°s¡± µî ÀÌ´Ù. ¹®ÀÚ¿(strings – string°ú strings¿Í ±¸ºÐ)Àº ¡°char *¡±·Î ÇØ¾ß Çϸç, insmod´Â ±× ¹®ÀÚ¿(strings)À» À§ÇÑ ¸Þ¸ð¸®¸¦ ÇÒ´çÇÑ´Ù. ´Ã º¯¼ö¸¦ ÃʱâÈÇÏ´Â ½À°üÀ» °®±æ ±ÇÇÑ´Ù. ÀÌ°ÍÀº Ä¿³Î ÄÚµåÀÌ´Ù. ´ç½ÅÀº ¹Ýµå½Ã ¹æ¾îÀûÀ¸·Î ÇÁ·Î±×·¡¹Ö ÇØ¾ß ÇÑ´Ù. ´ÙÀ½Àº ¿¹Á¦´Ù.
int myint = 3;
char *mystr; MODULE_PARM (myint, "i"); MODULE_PARM (mystr, "s");
int myshortArray[4];
MODULE_PARM (myintArray, "2-4i"); Example 2-7. hello-5.c
/* hello-5.c - Demonstrates command line argument passing to a module. */
#include <linux/module.h> #include <linux/kernel.h> #include <linux/init.h> MODULE_LICENSE("GPL"); MODULE_AUTHOR("Peiter Jay Salzman"); static short int myshort = 1; static int myint = 420; static long int mylong = 9999; static char *mystring = "blah"; MODULE_PARM (myshort, "h"); MODULE_PARM (myint, "i"); MODULE_PARM (mylong, "l"); MODULE_PARM (mystring, "s"); 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); Supercalifragilisticexpialidocious(ÀúÀÚ°¡ ¾´ ¾ÏÈ£ Áß Çϳª... -_-)
3.7. ´ÙÁß ÆÄÀÏ ¸ðµâ ¶¶§·Î´Â Ä¿³Î ¸ðµâÀ» ¿©·¯ °³ÀÇ ¼Ò½ºÆÄÀÏ·Î ³ª´©´Â °ÍÀÌ ÁÁÀ» ¶§°¡ ÀÖ´Ù. ÀÌ·± °æ¿ì ´ÙÀ½°ú °°Àº »çÇ×ÀÌ ÇÊ¿äÇÏ´Ù.
Example 2-8. start.c
/* start.c - Illustration of multi filed modules */
#include <linux/kernel.h> /* We're doing kernel work */ #include <linux/module.h> /* Specifically, a module */ 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 */
#if defined(CONFIG_MODVERSIONS) && ! defined(MODVERSIONS) #include <linux/modversions.h> /* Will be explained later */ #define MODVERSIONS #endif #include <linux/kernel.h> /* We're doing kernel work */ #include <linux/module.h> /* Specifically, a module */ #define __NO_VERSION__ /* It's not THE file of the kernel module */ #include <linux/version.h> /* Not included by module.h because of __NO_VERSION__ */ void cleanup_module() { printk("<1>Short is the life of a kernel module\n"); } ¸¶Áö¸·À¸·Î Makefile
Example 2-10. Makefile for a multi-filed module
CC=gcc
MODCFLAGS := -O -Wall –DMODULE -D__KERNEL__ hello.o: hello2_start.o hello2_stop.o ld -m elf_i386 -r -o hello2.o hello2_start.o hello2_stop.o start.o: hello2_start.c ${CC} ${MODCFLAGS} -c hello2_start.c stop.o: hello2_stop.c ${CC} ${MODCFLAGS} -c hello2_stop.c 4.1.1. ¸ðµâÀº ¾î¶»°Ô ½ÃÀÛÇÏ°í ³¡³ª´Â°¡ ¶ÀϹÝÀûÀ¸·Î ÇÁ·Î±×·¥Àº main()ÇÔ¼ö¿¡¼ ½ÃÀÛÇÑ´Ù, ¸í·É¾îµéÀÇ ÁýÇÕÀ» ½ÇÇàÇÏ°í ¸í·É¾îµéÀÇ ¿Ï·á ½Ã Á¾·áµÈ´Ù. Ä¿³Î ¸ðµâÀº ¾à°£ ´Ù¸£°Ô ÀÛµ¿ÇÑ´Ù. ¸ðµâÀº Ç×»ó init_module()ÇÔ¼ö, ȤÀº ´ç½ÅÀÌ module_init()¶ó´Â ÇÔ¼ö¿¡ ÁöÁ¤ÇÑ °÷¿¡¼ ½ÃÀÛÇÑ´Ù. ÀÌ°ÍÀÌ ¸ðµâÀÇ ÁøÀÔ ÇÔ¼ö´Ù(entry function); ¸ðµâÀÌ ÇÊ¿äÇØÁú ¶§ ÀÌ ÇÔ¼öµéÀº Ä¿³Î¿¡°Ô ±× ¸ðµâÀÇ ±â´ÉÀº ¹«¾ùÀÌ¸ç ¾î¶»°Ô ¼³Á¤µÇ´Â °¡¸¦ ¾Ë·Á ÁØ´Ù. ÀÌ·± ¼³Á¤ÀÌ ÀÌ·ïÁö¸é ¸ðµâÀ» ½ÃÀÛÇÏ´Â ÇÔ¼ö´Â ¸®ÅÏÇÏ°í ¸ðµâÀÌ Á¦°øÇÏ´Â Äڵ带 °¡Áö°í Ä¿³ÎÀÌ ¹«¾ùÀΰ¡¸¦ ÇÏ·ÁÇÒ ¶§±îÁö ¸ðµâÀº ¾Æ¹«·± ÀÏÀ» ÇÏÁö ¾Ê´Â´Ù.
¸ðµç ¸ðµâÀº cleanup_module(), ȤÀº module_exit()¿¡ ÁöÁ¤µÇ ÀÖ´Â ÇÔ¼ö¸¦ È£ÃâÇÒ ¶§ Á¾·áµÈ´Ù. ÀÌ°ÍÀÌ ¸ðµâÀÇ Á¾·á ÇÔ¼ö(exit function)°¡ µÈ´Ù. ÀÌ ÇÔ¼ö´Â ÁøÀÔ ÇÔ¼ö°¡ ¹«¾ùÀ» ÇÏ´ø Á¾·á ½ÃŲ´Ù. ÁøÀÔ ÇÔ¼ö¿¡ µî·ÏµÇ ÀÖ´Â ±â´ÉÀ» ÇØÁ¦ÇÑ´Ù..
¸ðµç ¸ðµâÀº ÁøÀÔÇÔ¼ö¿Í Á¾·áÇÔ¼ö¸¦ °®´Â´Ù. Çϳª ÀÌ»óÀÇ ÁøÀÔÇÔ¼ö¿Í Á¾·áÇÔ¼ö¸¦ ÁöÁ¤ÇÏ´Â ¹æ¹ýÀÌ Àֱ⿡, `ÁøÀÔÇÔ¼ö(entry function)'¿Í `Á¾·áÇÔ¼ö(exit function)'¶ó´Â ´Ü¾î¸¦ »ç¿ëÇÏ°Ú´Ù. ±×·¯³ª ³»°¡ °£´ÜÈ÷ init_module() ±×¸®°í cleanup_module()À̶ó ÇÏ´õ¶óµµ, µ¶ÀÚµéÀº ³»°¡ ¹«¾ùÀ» ÀǹÌÇÏ´ÂÁö ¾Ë °ÍÀ̶ó »ý°¢ÇÏ°Ú´Ù.
4.1.2. ¸ðµâ¿¡ »ç¿ë °¡´ÉÇÑ ÇÔ¼öµé ¶ÇÁ·Î±×·¡¸ÓµéÀº ÀڽŵéÀÌ Á¤ÀÇÇÑ ÇÔ¼ö¸¸À» »ç¿ëÇÏ´Â °ÍÀº ¾Æ´Ï´Ù. ´ëÇ¥ÀûÀÎ ¿¹°¡ printf()´Ù. ÇÁ·Î±×·¡¸ÓµéÀº Ç¥ÁØ C¶óÀ̺귯¸®¿¡¼ Á¦°øÇÏ´Â ÀÌ·± ¶óÀ̺귯¸® ÇÔ¼öµéÀ» »ç¿ëÇÑ´Ù. ½ÇÁ¦ ÀÌ·± ÇÔ¼öµéÀÇ Á¤ÀÇ´Â ¸µÅ· ½ºÅ×ÀÌÁö(linking stage)°¡ µÉ ¶§±îÁö ÇÁ·Î±×·¥¿¡ µé¾î°¡Áö ¾Ê´Â´Ù. ±×¸®°í ÀÌ·± °ÍÀº Äڵ尡 »ç¿ë °¡´ÉÇÏ´Ù´Â °ÍÀ» º¸ÀåÇØÁÖ°í ±× À§Ä¡¿¡ ¸í·É¾î(instruction)¸¦ À§Ä¡ ½ÃÄÑÁØ´Ù.
¿©±â¼µµ Ä¿³Î ¸ðµâÀº ´Ù´Â ¾ç»óÀ» ¶í´Ù. Àü¼úÇÑ ¿¹Á¦¿¡¼, ¿ì¸®´Â printk()¶ó´Â ÇÔ¼ö¸¦ »ç¿ëÇß´Ù ±×¸®°í ±×°ÍÀº Ç¥ÁØ ¶óÀ̺귯¸® ÇÔ¼ö°¡ ¾Æ´ÔÀ» ¾Ë °ÍÀÌ´Ù. ¸ðµâÀº insmod¿¡ ÀÇÇØ Çؼ®µÇÁö´Â ½Éº¼À» °®´Â ¿ÀºêÁ§Æ® ÆÄÀÏÀ̱⠶§¹®ÀÌ´Ù. ½Éº¼ÀÇ Á¤ÀÇ´Â Ä¿³Î ÀÚü¿¡ ÀÖ´Ù. ´ç½ÅÀÌ »ç¿ë °¡´ÉÇÑ À¯ÀÏÇÑ ¿ÜºÎ ÇÔ¼ö´Â Ä¿³Î¿¡ ÀÇÇØ Á¦°øµÇ´Â °Íµé¿¡ ÇÑÁ¤µÇ¾îÁø´Ù. ¾î¶² ½Éº¼(¿ªÁÖ-¸ðµâ¿¡¼ Á÷Á¢ Á¤ÀÇÇÏÁö ¾Ê°í »ç¿ëÇÒ ¼ö ÀÖ´Â ÇÔ¼ö)µéÀÌ »ç¿ë°¡´ÉÇÑÁö ±Ã±ÝÇÏ´Ù¸é /proc/ksymsÀ» »ìÆìºÁ¶ó.
¶óÀ̺귯¸® ÇÔ¼ö¿Í ½Ã½ºÅÛ ÄÝÀÇ Â÷ÀÌÁ¡À» ¸í½ÉÇÏÀÚ. ¶óÀ̺귯¸® ÇÔ¼öµéÀº »óÀ§ ·¹º§¿¡ ÀÖÀ¸¸é¼, ¿Ïº®ÇÏ°Ô À¯Àú ·¹º§¿¡¼ ½ÇÇàµÇ¸ç, ÇÁ·Î±×·¡¸Ó°¡ ½ÇÁ¦ ÀÛ¾÷À» Çϴµ¥ ÆíÀǸ¦ Á¦°øÇØÁØ´Ù. ½Ã½ºÅÛ ÄÝÀº Ä¿³Î¿¡ ÀÇÇØ Á¦°øµÇ¸ç »ç¿ëÀÚÀÇ ÇàÀ§¿¡ µû¶ó Ä¿³Î ·¹º§¿¡¼ ½ÇÇàµÈ´Ù. ¶óÀ̺귯¸® ÇÔ¼öÀÎ printf()´Â °¡Àå ÀϹÝÀûÀÎ Ãâ·ÂÇÔ¼öó·³ º¸ÀδÙ. ±×·¯³ª ±×°ÍÀÌ ½ÇÁ¦·Î ÇÏ´Â ÀÏÀº µ¥ÀÌÅ͸¦ ½ºÆ®¸µÀ¸·Î Æ÷¸ËÇÏ°í ½ºÆ®¸µ µ¥ÀÌÅ͸¦ ·Î¿ì·¹º§ ½Ã½ºÅÛ ÄÝÀÎ write()¸¦ ÀÌ¿ëÇÏ´Â °ÍÀÌ´Ù, ±×¸®°í ±×°ÍÀº ±× µ¥ÀÌÅ͸¦ Ç¥ÁØ Ãâ·ÂÀ¸·Î ³»º¸³½´Ù.
Printf()°¡ ¹«¾ùÀ¸·Î ±¸¼ºµÇÀÖ´Â º¸°í ½ÍÀº°¡? ±×°ÍÀ» ¾Ë¾Æº¸´Â °ÍÀº ±²ÀåÈ÷ ½±´Ù. ´ÙÀ½ÀÇ ÇÁ·Î±×·¥À» ÄÄÆÄÀÏ Çغ¸ÀÚ.
#include <stdio.h>
int main(void) { printf("hello"); return 0; } ´ç½Åµµ Ä¿³ÎÀÇ ½Ã½ºÅÛ ÄÝÀ» ´ëüÇϱâ À§ÇØ ¸ðµàÀ» ¾µ °ÍÀÌ´Ù.(¿ì¸®°¡ °£´ÜÈ÷ ÇÒ°ÍÀÌ´Ù) Å©·¡Ä¿µéÀÌ ¹éµµ¾î¿ëÀ¸·Î ÀÌ·± Á¾·ùÀÇ °ÍµéÀ» »ç¿ëÇÑ´Ù. ´©±º°¡ ´ç½ÅÀÇ ½Ã½ºÅÛ¿¡ ÀÖ´Â ÆÄÀÏÀ» Áö¿ì·Á ½ÃµµÇÒ ¶§¸¶´Ù ´ç½ÅÀº ¸ðµâÀ» ÀÌ¿ëÇؼ ¡°°£Áö·¯ Àå³ Ä¡Áö¸¶¡±(¿ªÁÖTee hee, that tickles! ÀÇ¿ª)¶ó´Â ½ÄÀÇ ¿ÂÈÇÑ ´ëÀÀÀ» ÇÒ ¼ö ÀÖÀ» °ÍÀÌ´Ù.
4.1.3. »ç¿ëÀÚ °ø°£ vs Ä¿³Î °ø°£ ¶Ä¿³ÎÀº ºñµð¿À Ä«µå, ÇÏµå µå¶óÀ̺ê, ½ÉÁö¾î ¸Þ¸ð¸®±îÁö ¸ðµç ¸®¼Ò½º¿¡ Á¢±ÙÇÑ´Ù. ÇÁ·Î±×·¥Àº Á¾Á¾ °°Àº ¸®¼Ò½º¿¡ ´ëÇØ °æÀïÇÑ´Ù. ³»°¡ ÀÌ ¹®¼¸¦ ÀúÀåÇÒ ¶§, updatedb°¡ À§Ä¡¿¡´ëÇÑ µ¥ÀÌÅÍ º£À̽º¸¦ °»½ÅÇϱ⠽ÃÀÛÇÑ´Ù. ³ªÀÇ vim ¼¼¼Ç°ú updatedb°¡ °°Àº ÇÏµå µå¶óºê¸¦ µ¿½Ã¿¡ »ç¿ëÇÏ´Â °ÍÀÌ´Ù. Ä¿³ÎÀº ÀÌ·± °ÍµéÀ» ¼ø¼´ë·Î À¯ÁöÇÒ ÇÊ¿ä°¡ ÀÖÀ¸¸ç, »ç¿ëÀÚ°¡ ±×µéÀÌ ¿øÇÏ´Â ÀÚ¿ø¿¡ Á÷Á¢ Á¢±ÙÇϵµ·Ï ±ÇÇÑÀ» Á־ ¾È µÈ´Ù. ÀÌ·± ÀÌÀ¯·Î CPU´Â ´Ù¸¥ ¹æ½ÄÀ¸·Î ÀÛµ¿ÇÑ´Ù. °¢ ¸ðµå´Â ´ç½ÅÀÌ ½Ã½ºÅÛ¿¡ ÇÏ°íÀÚ ÇÏ´Â ÀÏ¿¡ ´ëÇÑ ¼·Î ´Ù¸¥ ·¹º§ÀÇ ±ÇÇÑÀ» ÁØ´Ù. ÀÎÅÚÀÇ 30386 ¾ÆÅ°ÅØÃÄ´Â 4°³ÀÇ ¸ðµå¸¦ °¡Áö°í ÀÖ´Ù. À¯´Ð½º´Â ¸ðµç °ÍÀÌ °¡´ÉÇÑ °ü¸®ÀÚ ¸ðµå·Î ¾Ë·ÁÁø 0 ¸ðµå(ÃÖ»óÀ§ ¸ðµå – ringÀÇ ´Ü¾î¼±ÅÃÀÌ... -_-)¿Í À¯Àú ¸ðµå·Î ºÒ¸®´Â ÃÖÇÏÀ§ ¸ðµå, µÎ °¡Áö¸¸À» »ç¿ëÇÑ´Ù.
¶óÀ̺귯¸® ÇÔ¼ö¿Í ½Ã½ºÅÛ ÄÝ¿¡ ´ëÇÑ ³íÀǸ¦ »ó±âÇÏÀÚ. ´ç½ÅÀº ÀüÇüÀûÀ¸·Î »ç¿ëÀÚÀ¯Àú¸ðµå¿¡¼ ¶óÀ̺귯¸® ÇÔ¼ö¸¦ »ç¿ëÇÑ´Ù. ¶óÀ̺귯¸® ÇÔ¼ö´Â Çϳª ȤÀº ±× ÀÌ»óÀÇ ½Ã½ºÅÛ ÄÝÀ» È£ÃâÇÑ´Ù. ±×¸®°í ÀÌ·± ½Ã½ºÅÛ ÄÝÀº ¶óÀ̺귯¸® ÇÔ¼öó·³ ÇൿÇÑ´Ù. ±×·± °ü¸®ÀÚ ¸ðµå¿¡¼´Â Ä¿³ÎÀÇ ÀϺÎÀ̱⠶§¹®¿¡ ±×·¸°Ô ÇൿÇÑ´Ù. ½Ã½ºÅÛÄÝÀÌ ±× ÀÛ¾÷À» ¿Ï·áÇÏ¸é º¹±Í(return)ÇÏ°í À¯Àúº¸µå·Î º¹±ÍÇÑ´Ù.
4.1.4. À̸§ °ø°£ ¶´ç½ÅÀÌ CÇÁ·Î±×·¥À» ÀÛ¼ºÇÒ ¶§, ´ç½ÅÀº Äڵ带 º¸´Â »ç¶÷µéÀÇ °¡µ¶¼ºÀ» À§ÇØ º¯¼öÀ̸§À» »ç¿ëÇßÀ» °ÍÀÌ´Ù. ±Ô¸ð°¡ Å« ÇÁ·Î±×·¥ÀÇ ÀϺθ¦ ÀÛ¼ºÇÏ°í ÀÖÀ» ¶§, ´ç½ÅÀÇ Àü¿ªº¯¼ö°¡ °°ÀÌ ÀÏÇÏ´Â »ç¶÷ÀÇ Àü¿ªº¯¼öÀÇ À̸§°ú °°´Ù¸é º¯¼öÀ̸§À¸·Î ÀÎÇØ ¹®Á¦°¡ µÉ ¼ö ÀÖ´Ù. ¼·Î ±¸ºÐÇÒ ¸¸Å ÀÇ¹Ì ÀÖ´Â À̸§À» °®Áö ¸øÇÑ Àü¿ªº¯¼ö°¡ ¸¹ÀÌ Á¸ÀçÇÑ´Ù¸é À̸§°ø°£ÀÌ ¿À¿°µÉ °ÍÀÌ´Ù. ´ë±Ô¸ð ÇÁ·ÎÁ§Æ®¿¡¼ »ç¿ë º¸·ùµÈ À̸§¿¡ ´ëÇØ ÀÌ·± ³ë·ÂÀº ¹Ýµå½Ã ÀÖ¾î¾ß Çϸç, ½Éº¼°ú º¯¼öÀÇ À¯´ÏÅ©ÇÑ ¸í¸í ¹ý¿¡ ´ëÇÑ °èȹÀÌ ÇÊ¿äÇÏ´Ù.
Ä¿³Î Äڵ带 ÀÛ¼ºÇÒ ¶§ ±×°ÍÀÌ ¾Æ¹«¸® ÀÛÀº ¸ðµâÀÌ¶óµµ Ä¿³Î Àüü¿¡ ¸µÅ©µÇ±â ¶§¹®¿¡ ÀÌ°ÍÀº ºÐ¸í ¹®Á¦°¡ µÈ´Ù. ÀÌ°ÍÀ» ÇØ°áÇÏ´Â °¡Àå ÁÁÀº ¹æ¹ýÀº º¯¼ö¸¦ Á¤Àû º¯¼ö·Î ¼±¾ðÇÏ°í, Àß Á¤ÀÇµÈ Á¢µÎ¾î¸¦ ´ç½ÅÀÇ ½Éº¼¿¡ »ç¿ëÇÏ´Â °ÍÀÌ´Ù. °ü½ÀÀûÀ¸·Î Ä¿³ÎÀÇ Á¢µÎ¾î´Â ¼Ò¹®ÀÚ´Ù. ¸ðµç °ÍÀ» Á¤ÀûÀ¸·Î ¼±¾ðÇϱ⠿øÄ¡ ¾Ê´Â´Ù, symbol tableÀ» ¼±¾ðÇÏ°í ±×°ÍÀ» Ä¿³Î¿¡ µî·Ï½ÃÅ°´Â ¹æ¹ýÀ» ¾´´Ù. Â÷ÈÄ¿¡ ÀÌ°ÍÀ» ÇÏ°Ô µÉ °ÍÀÌ´Ù.
/proc/ksyms´Â Ä¿³ÎÀÌ ¾Ë°í ÀÖ´Â ¸ðµç ½Éº¼À» °¡Áö°í ÀÖ°í, ±× ½Éº¼Àº Ä¿³Î ÄÚµå ½ºÆäÀ̽º¿¡¼ °øÀ¯µÇ±â ¶§¹®¿¡, ´ç½ÅÀÇ ¸ðµâÀÌ Á¢±Ù/»ç¿ëÇÒ ¼ö ÀÖ´Ù.
4.1.5. ÄÚµå ¿µ¿ª ¶¸Þ¸ð¸® °ü¸®´Â ¸Å¿ì º¹ÀâÇÑ ÁÖÁ¦´Ù. `Understanding The Linux KernelÀÇ »ó´ç ºÎºÐÀÌ ¸Þ¸ð¸® °ü¸®¿¡ ÁßÁ¡À» µÐ´Ù. ¿ì¸®´Â ºñ·Ï ¸Þ¸ð¸® °ü¸®¿¡ Àü¹®°¡´Â ¾Æ´ÏÁö¸¸ ½ÇÁ¦ ¸ðµâÀ» ÀÛ¼ºÇϴµ¥ °í·ÁÇØ¾ß ÇÒ µÎ °¡Áö »ç½Ç¿¡ ´ëÇØ ¾Ë ÇÊ¿ä´Â ÀÖ´Ù.
½ÇÁ¦·Î ¼¼±×¸àÆ® ÆúÆ®°¡ ¹«¾ùÀ» ÀǹÌÇÏ´ÂÁö »ý°¢Çغ¸Áö ¾Ê¾Ò´Ù¸é Æ÷ÀÎÅÍ°¡ ½ÇÁ¦ ¸Þ¸ð¸® À§Ä¡¸¦ Áö½ÃÇÏ°í ÀÖÁö ¾Ê´Ù´Â °ÍÀ» µè°Ô µÇ¸é ³î¶ö °ÍÀÌ´Ù. ¾î·µç ¾î´À Æ÷ÀÎÅ͵µ ±×·¸Áö ¾Ê´Ù. ÇÁ·Î¼¼½º°¡ »ý¼ºµÉ ¶§, Ä¿³ÎÀº ½ÇÁ¦ ¸Þ¸ð¸®ÀÇ ÀϺθ¦ ÇÒ´çÇØ, (ÄÄÇ»ÅÍ ÇÐÀÚ³ª ¾Ë¹ýÇÑ °Íµé) ÇÁ·Î¼¼½º°¡ »ç¿ëÇÏ´Â ½ÇÇàÄÚµå, º¯¼ö, ½ºÅÃ, Èü µîÀ¸·Î »ç¿ëÇϵµ·Ï ÇÁ·Î¼¼½º¿¡°Ô ³Ñ±ä´Ù. ÀÌ ¸Þ¸ð¸®´Â $0$¿¡¼ ½ÃÀÛÇØ ÇÁ·Î¼¼½º°¡ ÇÊ¿äÇÑ ¸¸Å È®ÀåµÈ´Ù. ¼·Î ´Ù¸¥ µÎ ÇÁ·Î¼¼½ºÀÇ ¸Þ¸ð¸® ¿µ¿ªÀº °ãÄ¡Áö ¾Ê±â ¶§¹®¿¡ 0xbffff978¿¡ Á¢±ÙÇÏ´Â ¸ðµç ÇÁ·Î¼¼½º´Â ½ÇÁ¦ ¹°¸®Àû ¸Þ¸ð¸®ÀÇ ¼·Î ´Ù¸¥ ÁöÁ¡¿¡ Á¢±ÙÇÒ °ÍÀÌ´Ù. ÇÁ·Î¼¼½ºµéÀº ƯÁ¤ ÇÁ·Î¼¼½º¿¡°Ô ÇÒ´çµÈ ¸Þ¸ð¸® ¿µ¿ªÀ¸·ÎÀÇ ¿ÀÇÁ¼ÂÀÇ ÇÑ Á¾·ù¸¦ Áö½ÃÇÏ´Â 0xbffff978·Î À̸§ Áö¾îÁø À妽º¿¡ Á¢±ÙÇÏ·Á ÇÒ °ÍÀÌ´Ù. ÀÌÈÄ¿¡ ´Ù·ç°Ô µÉ ¹æ¹ýÀÌ ÀÖÀ½¿¡µµ ºÒ±¸ÇÏ°í, ¿ì¸®ÀÇ Hello, World¿Í °°Àº ´ëºÎºÐÀÇ °æ¿ì ´Ù¸¥ ÇÁ·Î¼¼½ºÀÇ ¿µ¿ª¿¡ Á¢±ÙÇÒ ¼ö ¾ø´Ù.
Ä¿³Î ¿ª½Ã ÀڽŸ¸ÀÇ ¸Þ¸ð¸® ¿µ¿ªÀÌ ÀÖ´Ù. ¸ðµâÀº µ¿ÀûÀ¸·Î Ä¿³Î¿¡ ÀûÀç µÇ°Å³ª Á¦°ÅµÉ ¼ö ÀÖ´Â ÄÚµå±â ¶§¹®¿¡, ¸ðµâÀº ÀڽŸ¸ÀÇ Ä¿³Î ÄÚµå ¿µ¿ªÀ» °¡Áö±â º¸´Ù´Â Ä¿³Î ÄÚµå ¿µ¿ªÀ» °øÀ¯ÇÑ´Ù. Áï, ¹Ý µ¶¸³Àû °´Ã¼¿¡ »ó¹ÝµÇ´Â °³³äÀÌ´Ù. (as opposed to a semi-autonomous object ÀÇ ÀÇ¿ª) ±×·¯¹Ç·Î ¿ì¸®ÀÇ ¼¼±×¸ÕÆ® ÆúÆ®´Â Ä¿³ÎÀÇ ¼¼±×¸ÕÆ® ÆúÆ®°¡ µÈ´Ù. off-by-one ¿¡·¯ ¶§¹®¿¡ µ¥ÀÌÅ͸¦ °ãÃÄ ¾²±â ½ÃÀÛÇÑ´Ù¸é, Ä¿³Î Äڵ带 ¸Á°¡Æ®¸± °ÍÀÌ´Ù. ÀÌ°Ç »ý°¢º¸´Ù ½É°¢ÇϹǷΠÁÖÀǸ¦ ±â¿ï¿©¾ß ÇÑ´Ù. ( off-by-one error : n=0¿¡¼ ½ÃÀÛÇÒ °ÍÀ» n=1¿¡¼ ½ÃÀÛÇÔÀ¸·Î Çؼ ÀϾ´Â ·ùÀÇ ¿¡·¯¸¦ ÀǹÌÇÔ)
À§¿¡¼ ¾ð±ÞÇÑ »ç½ÇµéÀº ¸ð³î¸®Æ½ Ä¿³ÎÀ» »ç¿ëÇÏ´Â ¸ðµç ¿ÀÆÛ·¹ÀÌÆà ½Ã½ºÅÛ¿¡¼ Àû¿ëµÈ´Ù´Â °ÍÀ» ÁöÀûÇÏ°í ½Í´Ù. ÀÚ±â ÀڽŸ¸ÀÇ ÄÚµå ¿µ¿ªÀ» °®´Â ¸¶ÀÌÅ©·Î Ä¿³ÎÀ̶ó´Â °Íµµ ÀÖ´Ù. GNU Hurd¿Í QNX Neutrino°¡ ¸¶ÀÌÅ©·Î Ä¿³ÎÀÇ ¿¹´Ù.
4.1.6. ÀåÄ¡ µå¶óÀ̹ö ¶¸ðµâÀÇ ÇÑ Á¾·ù°¡ ÀåÄ¡ µå¶óÀ̹öÀ̸ç, ±×µéÀº TVÄ«µå³ª ½Ã¸®¾ó Æ÷Æ® °°Àº Çϵå¿þ¾îÀÇ ±â´ÉÀ» Á¦°øÇÑ´Ù. À¯´Ð½º¿¡¼ ÇϳªÀÇ Çϵå¿þ¾î´Â Çϵå¿þ¾î¿Í ÀÇ»ç Åë½ÅÇÏ´Â ¼ö´ÜÀ» Á¦°øÇÏ´Â named device ÆÄÀÏ(/dev/ ¾Æ·¡ À§Ä¡ÇÑ´Ù.)·Î º¸¿©Áø´Ù. µð¹ÙÀ̽º µå¶óÀ̹ö´Â À¯Àú ÇÁ·Î±×·¥À» ´ë½ÅÇØ, ÀÇ»ç ¼ÒÅë ¼ö´ÜÀ» Á¦°øÇÑ´Ù. es1370 »ç¿îµåÄ«µå µå¶óÀ̹ö´Â Ensoniq IS1370 »ç¿îµå Ä«µå¿¡ ¿¬°áÇϱâ À§ÇØ /dev/sound device¿¡ ¿¬°áÇÑ´Ù. mp3blaster¿Í °°Àº À¯Àú ½ºÆäÀ̽º ÇÁ·Î±×·¥Àº ¾î¶² Á¾·ùÀÇ »ç¿îµå Ä«µå°¡ ¼³Ä¡µÆ´ÂÁö ¸ð¸¥ ü /dev/sound¶ó´Â ÀåÄ¡¸¦ »ç¿ëÇÒ ¼ö ÀÖ´Ù.
4.1.6.1. ÀåÄ¡ ÁÖ ¹øÈ£¿Í ÀåÄ¡ ºÎ ¹øÈ£ ¶µð¹ÙÀ̽º ÆÄÀÏÀ» »ìÆ캸ÀÚ. ´ÙÀ½Àº ÇÁ¶óÀ̸Ӹ® ¸¶½ºÅÍ 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 ÄÞ¸¶¿¡ ÀÇÇØ ±¸ºÐµÈ ¹øÈ£ÀÇ ¿À» ÁÖ½ÃÇÏÀÚ Ã¹ ¹ø° ¹øÈ£¸¦ ÀåÄ¡ ÁÖ ¹øÈ£¶ó ºÎ¸£¸ç µÎ ¹ø° ¹øÈ£´Â ºÎ ¹øÈ£¶ó ºÎ¸¥´Ù. ÁÖ ¹øÈ£´Â µå¶óÀ̹ö°¡ ¾î¶² Çϵå¿þ¾î¿¡ ¿¢¼¼½ºÇÏ´ÂÁö ¾Ë·ÁÁØ´Ù. °¢ µå¶óÀ̹ö´Â À¯ÀÏÇÑ ÁÖ ¹øÈ£¸¦ ÇÒ´ç ¹ÞÀ¸¸ç, µ¿ÀÏÇÑ ÁÖ ¹øÈ£¸¦ °®´Â ¸ðµç µð¹ÙÀ̽º ÆÄÀÏÀº °°Àº µå¶óÀ̹ö¿¡ ÀÇÇØ ÄÁÆ®·Ñ µÈ´Ù. À§ÀÇ ÁÖ ¹øÈ£°¡ ¸ðµÎ 3ÀÎ °ÍÀº, ±×µéÀÌ °°Àº µå¶óÀ̹ö¿¡ ÀÇÇØ ÄÜÆ®·Ñ µÇ±â ¶§¹®ÀÌ´Ù.
ºÎ ¹øÈ£´Â µå¶óÀ̹ö°¡ ÀÚ½ÅÀÌ ÄÁÆ®·ÑÇÏ´Â Çϵå¿þ¾î¸¦ ±¸ºÐÇϱâ À§ÇØ »ç¿ëµÈ´Ù. À§ÀÇ ¿¹·Î µ¹¾Æ°¡ º¸ÀÚ, ¼¼ °³ÀÇ ÀåÄ¡µéÀÌ °°Àº µå¶óÀ̹ö¿¡ ÀÇÇØ ¿î¿µµÉÁö¶óµµ ¼·Î ´Ù¸¥ °íÀ¯ÀÇ ºÎ ¹øÈ£¸¦ °®´Âµ¥, ÀÌ´Â µå¶óÀ̹ö°¡ ±×µé(ÇÏµå µð½ºÅ© ÆÄƼ¼Çµé)À» ¼·Î ´Ù¸¥ Çϵå¿þ¾î·Î ÀνÄÇϱ⠶§¹®ÀÌ´Ù.
µð¹ÙÀ̽º´Â ij¸¯ÅÍ µð¹ÙÀ̽º¿Í ºí·Ï µð¹ÙÀ̽ºÀÇ µÎ ŸÀÔÀ¸·Î ³ª´¶´Ù. ºí·Ï µð¹ÙÀ̽º´Â ¹öÆÛ¸¦ °¡Áö°í ÀÖ¾î, ¾î¶² ¼ø¼·Î ÀÀ´äÇÏ´Â °ÍÀÌ °¡Àå ÁÁÀº °ÍÀΰ¡ ¼±ÅÃÇÒ ¼ö ÀÖ´Ù´Â °ÍÀÌ Â÷ÀÌÁ¡ÀÌ´Ù. ÀÌÁ¡Àº ¹°¸®ÀûÀ¸·Î ¶³¾îÁ®ÀÖ´Â ¼½Åͺ¸´Ù °¡±îÀÌ ÀÖ´Â ¼½ÅÍ¿¡ Àбâ/¾²±â¸¦ ÇÏ´Â °ÍÀÌ ºü¸£´Ù´Â Á¡¿¡¼ ÀúÀå ÀåÄ¡¿¡ ÀÖ¾î Áß¿äÇÏ´Ù. ¶Ç ´Ù¸¥ Â÷ÀÌÁ¡Àº ºí·Ï µð¹ÙÀ̽º¸¸ÀÌ ÀÔÃâ·Â ½Ã ºí·Ï ´ÜÀ§·Î Á¢±ÙÇÒ ¼ö ÀÖ´Ù´Â Á¡ÀÌ´Ù(ºí·ÏÀÇ Å©±â´Â ÀåÄ¡¿¡ µû¶ó ´Ù¸£´Ù). ¹Ý¸é¿¡ ij¸¯ÅÍ µð¹ÙÀ̽º´Â ¸î ¹ÙÀÌÆ® µÇÁö ¾Ê´Â Å©±â¸¸À» Çã¿ëÇÑ´Ù. ´ëºÎºÐÀÇ ÀåÄ¡´Â ij¸¯ÅÍ µð¹ÙÀ̽ºÀÌ´Ù. ¿Ö³ÄÇϸé ÀåÄ¡µé ´ëºÎºÐÀÌ ÀÌ·± Á¾·ùÀÇ ¹öÆÛÀÏÀ» ÇÊ¿ä·Î ÇÏÁö ¾Ê°í °íÁ¤µÈ ºí·Ï Å©±â¿¡ ´ëÇØ ÀÛµ¿ÇÏÁö ¾Ê±â ¶§¹®ÀÌ´Ù. ls –lÀÇ °á°ú¿¡¼ ù ¹ø° ¹®ÀÚ¸¦ »ìÆì º½À¸·Î½á µð¹ÙÀ̽º°¡ ºí·Ï µð¹ÙÀ̽ºÀÎÁö ij¸¯ÅÍ µð¹ÙÀ̽ºÀÎÁö ±¸ºÐÇÒ ¼ö ÀÖ´Ù. ¸¸ÀΠù ¹®ÀÚ°¡ ¡®b¡¯ÀÌ¸é ºí·Ïµð¹ÙÀ̽º°í, ¡®c¡¯À̸é ij¸¯ÅÍ µð¹ÙÀ̽ºÀÌ´Ù. ´ÙÀ½Àº ij¸¯ÅÍ µð¹ÙÀ̽ºÀÇ ¿¹´Ù(½Ã¸®¾ó Æ÷Æ®).
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¿¡ ÀÇÇØ »ý¼ºµÈ´Ù. ÁÖ¹øÈ£/ºÎ¹øÈ£ 12, 2ÀÇ ¡®coffee¡¯¶ó´Â »õ·Î¿î ij¸¯ÅÍ µð¹ÙÀ̽º¸¦ »ý¼ºÇÏ°íÀÚ ÇÑ´Ù¸é, ´Ü¼øÈ÷ mknod /dev/coffee c 12 2¸¸ ½ÇÇà½ÃÅ°¸é µÈ´Ù. µð¹ÙÀ̽º ÆÄÀÏÀ» /dev/¿¡ ³ÖÀ» ÇÊ¿ä´Â ¾ø´Ù. ´Ü¼øÈ÷ °ü½ÀÀÏ »ÓÀÌ´Ù. ¸®´©Áî°¡ ±×ÀÇ µð¹ÙÀ̽º ÆÄÀÏÀ» /dev/¿¡ ³Ö¾ú±â ¶§¹®¿¡ ´ç½Åµµ ±×·¸°Ô ÇÏ´Â °ÍÀÌ ³´À» °ÍÀÌ´Ù. ±×·¯³ª Å×½ºÆ® ¸ñÀûÀ¸·Î µð¹ÙÀ̽º ÆÄÀÏÀ» »ý¼ºÇÑ´Ù¸é, Ä¿³Î ¸ðµâÀ» ÄÄÆÄÀÏÇÑ ÀÛ¾÷ µð·ºÅ丮¿¡ µð¹ÙÀ̽º ÆÄÀÏÀ» ³Ö¾îµµ ¹«¹æÇÏ´Ù. µð¹ÙÀ̽º µå¶óÀ̹ö ÀÛ¼ºÀÌ ¿Ï·áµÆÀ» ¶§ ¿Ã¹Ù¸¥ À§Ä¡¿¡¸¸ ³ÖÀ¸¸é µÈ´Ù.
³ª´Â ÀÌÀü¿¡ ¾ð±ÞÇß´ø °Íµé°ú »óÃæµÇ´Â ¸î °¡Áö ÁöÀûÀ» Çϱ⸦ ÁÁ¾Æ ÇÑ´Ù. ÇÏÁö¸¸ ±×°ÍµéÀº ´ÜÁö ¸î¸î °æ¿ì¿¡¸¸ ±¹ÇѵȴÙ. µð¹ÙÀ̽º ÆÄÀÏÀÌ ¾×¼¼½ºµÉ ¶§ Ä¿³ÎÀº ÀåÄ¡ ÁÖ ¹øÈ£¸¦ ¾î¶² µå¶óÀ̹ö¸¦ ÀÌ¿ëÇØ ±× ¾×¼¼½º¸¦ ó¸®ÇÒ °ÍÀΰ¡¸¦ °áÁ¤Çϱâ À§ÇØ »ç¿ëÇÑ´Ù. ÀÌ À̾߱â´Â Ä¿³ÎÀº ÀåÄ¡ ºÎ ¹øÈ£¸¦ »ç¿ëÇÒ ÇÊ¿ä°¡ ¾ø°í, ½ÉÁö¾î ¸ô¶óµµ µÈ´Ù´Â ¸»ÀÌ´Ù. ÀåÄ¡ ºÎ ¹øÈ£¿¡ °ü½ÉÀ» °®´Â °ÍÀº µå¶óÀ̹ö ÀÚü »ÓÀÌ´Ù. µ¿ÀÏÇÑ Á¾·ùÀÇ Çϵå¿þ¾î Áß¿¡ ¾î¶² ÀåÄ¡Àΰ¡¸¦ ±¸ºÐÇϱâ À§Çؼ¸¸ ÀåÄ¡ ºÎ ¹øÈ£´Â »ç¿ëµÈ´Ù.
±×·±µ¥ ³»°¡ ¡®Çϵå¿þ¾î¡¯¶ó°í ÇßÀ» ¶§, ³ ´ç½ÅÀÇ ¼Õ¿¡ ÀÖ´Â 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ÀÌÁ¦ µÎ °³ÀÇ µð¹ÙÀ̽º ÆÄÀÏÀ» º¸°í ±×µéÀÌ ºí·Ï µð¹ÙÀ̽º¶ó´Â °Í°ú µ¿ÀÏÇÑ µå¶óÀ̹ö¿¡ ÀÇÇØ Ã³¸®µÈ´Ù´Â °ÍÀ» Áï½Ã ¾Ë ¼ö ÀÖÀ» °ÍÀÌ´Ù. µÎ °³ÀÇ µð¹ÙÀ̽º ÆÄÀÏÀº ´ç½ÅÀÇ Ç÷ÎÇÇ µå¶óÀ̺긦 ³ªÅ¸³½´Ù´Â °ÍÀ» ¾Ë °ÍÀÌ´Ù. ±×·±µ¥ ´ç½ÅÀº ÇϳªÀÇ Ç÷ÎÇÇ µå¶óÀ̹ö¸¸À» °¡Áö°í ÀÖÁö ¾ÊÀº°¡. ¿Ö µÎ °³Àΰ¡? Çϳ 1.44MBÀÇ Ç÷ÎÇÇ µå¶óÀ̺긦 ³ªÅ¸³½´Ù. ´Ù¸¥ Çϳª´Â ÈçÈ÷ ¸»ÇÏ´Â ¡®superformatted¡¯ µå¶óÀ̺꿡 ÇØ´çµÇ´Â 1.68MBÀÇ µ¿ÀÏÇÑ ÀúÀå ÀåÄ¡´Ù. Ç¥ÁØ Æ÷¸Ë Ç÷ÎÇÇ º¸´Ù ¸¹Àº ¾çÀÇ µ¥ÀÌÅ͸¦ ÀúÀåÇÏ´Â °ÍÀÌ´Ù. ÀÌ°ÍÀÌ µ¿ÀÏÇÑ ½ÇÁ¦ Çϵå¿þ¾î¿¡ ¼·Î ´Ù¸¥ ÀåÄ¡ ºÎ ¹øÈ£¸¦ °®´Â °æ¿ì´Ù. ¿ì¸®ÀÇ ³íÀÇ¿¡¼ ¡®Çϵå¿þ¾î¡¯¶ó°í ÇÏ´Â ´Ü¾î°¡ »ó´çÈ÷ Ãß»óÀûÀ̶ó´Â °ÍÀ» ¾Ë±â ¹Ù¶õ´Ù. 5.1.1. file_operations ±¸Á¶Ã¼ ¶file_operations ±¸Á¶Ã¼´Â linux/fs.h¿¡ Á¤ÀÇµÇ ÀÖÀ¸¸ç ÀåÄ¡µé¿¡ ´ëÇØ ´Ù¾çÇÑ ÀÛµ¿À» ÇÏ´Â µå¶óÀ̹ö¿¡ ÀÇÇØ Á¤ÀÇµÈ ÇÔ¼öµéÀ» °¡Áö°í ÀÖ´Ù. ±¸Á¶Ã¼ÀÇ °¢ Çʵå´Â ¿ä±¸µÇ´Â ÀÛµ¿À» Çϱâ À§ÇØ µå¶óÀ̹ö¿¡ ÀÇÇØ Á¤ÀÇµÈ ÇÔ¼öµéÀÇ ÁÖ¼Ò¿¡ ´ëÀÀµÈ´Ù.
¿¹¸¦ µé¾î, ¸ðµç ¹®ÀÚ ÀåÄ¡ µå¶óÀ̹ö´Â ÀåÄ¡·ÎºÎÅÍ µ¥ÀÌÅ͸¦ ÀÐ¾î ¿À´Â ÇÔ¼ö¸¦ Á¤ÀÇ ÇÒ ÇÊ¿ä°¡ ÀÖ´Ù. file_operations ±¸Á¶Ã¼´Â ±×·± ±â´ÉÀ» ÇÏ´Â ÇÔ¼ö ¸ðµâÀÇ ÁÖ¼Ò¸¦ °¡Áö°í ÀÖ´Â °ÍÀÌ´Ù. Ä¿³Î 2.4.2¿¡¼ ±× Á¤ÀÇ´Â ´ÙÀ½°ú °°´Ù.
struct file_operations {
struct module *owner; loff_t (*llseek) (struct file *, loff_t, int); ssize_t (*read) (struct file *, char *, size_t, loff_t *); ssize_t (*write) (struct file *, const char *, 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 (*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 *); }; ¾î¶² µ¿ÀÛµéÀº µå¶óÀ̹ö¿¡ ÀÇÇØ ±¸ÇöµÇÁö ¾Ê´Â´Ù. ¿¹·Î ºñµð¿ÀÄ«µå¸¦ ´Ù·ç´Â µå¶óÀ̹ö´Â µð·ºÅ丮 ±¸Á¶Ã¼¿¡¼ µ¥ÀÌÅ͸¦ Àоî¿Ã ÇÊ¿ä´Â ¾ø´Ù. ÀÌ °æ¿ì file_operations±¸Á¶Ã¼ÀÇ ÇØ´ç Çʵå´Â NULL·Î ¼¼ÆõȴÙ.
gccÀÇ È®Àå ¹öÀüÀº ÀÌ ±¸Á¶Ã¼¿¡ ÀÎÀÚ ÇÒ´çÀ» Á»´õ ÆíÇÏ°Ô ÇØÁØ´Ù. ÃÖ±Ù ¸¸µé¾îÁø µå¶óÀ̹öµé¿¡¼ ÀÌ·± °ÍµéÀ» º¼ ¼ö ÀÖ´Ù, ¾Æ¸¶µµ (»ç¿ë ¹æ¹ý ¶§¹®¿¡) ³î¶ó¿òÀ» ÁÙ ¼öµµ ÀÖ´Ù. ´ÙÀ½Àº ÀÌ·± »õ·Î¿î ÇÒ´ç ¹æ½ÄÀ» º¸¿©ÁØ´Ù.
struct file_operations fops = {
read: device_read, write: device_write, open: device_open, release: device_release; } ±×·¯³ª C99¹æ½ÄÀÇ ±¸Á¶Ã¼ ¸â¹ö ÇÒ´ç¹æ½Äµµ ¿©ÀüÈ÷ Á¸ÀçÇϸç GNUÈ®Àå ¹öÀüÀ» »ç¿ëÇÔ¿¡ ¿ÀÈ÷·Á ÀÌ ¹æ½ÄÀÌ ¼±È£µÇ°í ÀÖ´Ù. ³»°¡ ÇöÀç »ç¿ëÇÏ°í ÀÖ´Â gcc 2.95¹öÀüÀº C99 ¹®¹ýÀÇ »õ·Î¿î ºÎºÐÀ» Áö¿øÇÏ°í ÀÖ´Ù. ´©±º°¡ ´ç½ÅÀÇ µå¶óÀ̹ö¸¦ Æ÷ÆÃÇϱ⠿øÇÏ´Â °æ¿ì ´ç½ÅÀº ÀÌ ¹®¹ýÀ» »ç¿ëÇØ¾ß ÇÒ °ÍÀÌ´Ù. ÀÌ °æ¿ì µÎ Á¾·ùÀÇ ½ÅÅؽº°¡ °øÁ¸ÇÒ ¼ö ÀÖ´Ù.
struct file_operations fops = {
.read = device_read, .write = device_write, .open = device_open, .release = device_release }; Àǹ̴ ¸íÈ®ÇÏ´Ù ±×¸®°í ´ç½ÅÀÌ ÇÒ´çÇÏÁö ¾ÊÀº ±¸Á¶Ã¼ÀÇ ¸â¹ö´Â gcc¿¡ ÀÇÇØ NULL·Î Ãʱâȵȴٴ »ç½ÇÀ» ±â¾ïÇÏÀÚ. file_operations ±¸Á¶Ã¼ÀÇ Æ÷ÀÎÅÍ´Â ÀϹÝÀûÀ¸·Î fops¶ó´Â À̸§À» °®´Â´Ù.
5.1.2. file ±¸Á¶Ã¼ ¶°¢°¢ÀÇ ÀåÄ¡µéÀº file±¸Á¶Ã¼¿¡ ÀÇÇØ Ä¿³Î ³»ºÎ¿¡ º¸¿©Áø´Ù. ±×¸®°í ±×°ÍÀº linux/fs.h¿¡ Á¤ÀÇ µÇÀÖ´Ù. ±¸Á¶Ã¼´Â Ä¿³Î ³»ºÎ¿¡ Á¸ÀçÇÏ¸ç »ç¿ëÀÚ °ø°£ÀÇ ÇÁ·Î±×·¥¿¡¼´Â Àý´ë º¸ÀÌÁö ¾Ê´Â´Ù´Â °ÍÀ» ¸í½ÉÇÏÀÚ. ±¸Á¶Ã¼¿Í °°Áö ¾Ê´Ù. FILE±¸Á¶Ã¼´Â glibc¿¡ Á¤ÀÇµÇ ÀÖ°í Ä¿³Î¿µ¿ª¿¡´Â Àý´ë º¸ÀÌÁö ¾Ê´Â´Ù. À̸§ ¶§¹®¿¡ À߸ø ÀÌÇصDZ⵵ ÇÑ´Ù. ±×°ÍÀº ¿¸° ÆÄÀÏÀ» ÀǹÌÇÏÁö µð½ºÅ©»óÀÇ inode±¸Á¶Ã¼¿¡ ÀÌÇØ Áö½ÃµÇ´Â ÆÄÀÏÀ» ÀǹÌÇÏ´Â °ÍÀº ¾Æ´Ï´Ù.
file±¸Á¶Ã¼ÀÇ Æ÷ÀÎÅÍ´Â ÀϹÝÀûÀ¸·Îfilp¶ó´Â À̸§À» °®´Â´Ù. struct file file¿Í È¥µ·ÇÏÁö ¸»ÀÚ(¿ÏÀü Åë¹ä-_-)
file±¸Á¶Ã¼ÀÇ Á¤ÀǸ¦ »ìÆ캸ÀÚ. ´ëºÎºÐÀÇ ¸â¹öµéÀÌ dentry±¸Á¶Ã¼Ã³·³ µð¹ÙÀ̽º µå¶óÀ̹ö¿¡¼ »ç¿ëµÇÁö ¾Ê´Â´Ù. ¶ÇÇÑ ±×·± ºÎºÐÀº ¹«½ÃÇصµ ÁÁ´Ù. µð¹ÙÀ̽º µå¶óÀ̹ö´Â file±¸Á¶Ã¼¸¦ Á÷Á¢ÀûÀ¸·Î ä¿ìÁö ¾Ê°í ¾îµð¼±°¡ »ý¼ºÇÑ ÆÄÀÏ ±¸Á¶Ã¼ÀÇ ³»¿ëÀ» ´ÜÁö ÀÌ¿ëÇϱ⸸ ÇÒ »ÓÀÌ´Ù.
5.1.3. Registering A Device ¶¾Õ¼ ³íÀÇÇÑ °Íó·³ ¹®ÀÚÀåÄ¡´Â º¸Åë dev1 ¿¡ ÀÖ´Â µð¹ÙÀ̽º ÆÄÀÏÀ» ÅëÇØ Á¢±ÙµÈ´Ù. ÁÖÀåÄ¡ ¹øÈ£´Â ¾î´À µå¶óÀ̹ö°¡ ¾î´Â µð¹ÙÀ̽º ÆÄÀÏÀ» »ç¿ëÇϴ°¡ ¾Ë·ÁÁØ´Ù. ºÎ ÀåÄ¡¹øÈ£´Â µå¶óÀ̹ö°¡ Çϳª ÀÌ»óÀÇ ÀåÄ¡¸¦ ÀÛµ¿½Ãų ¶§, ¾î¶² ÀåÄ¡°¡ °¡µ¿µÇ´Â°¡¸¦ ±¸ºÐÇϱâ À§ÇØ µå¶óÀ̹ö ³»ºÎ¿¡¼ »ç¿ëµÈ´Ù.
½Ã½ºÅÛ¿¡ µå¶óÀ̹ö¸¦ Ãß°¡ÇÑ´Ù´Â °ÍÀº Ä¿³Î¿¡ ±×°ÍÀ» µî·Ï½ÃÅ°´Â °ÍÀ» ÀǹÌÇÑ´Ù. ¸ðµâÀÌ ÃʱâȵǴ µ¿¾È ÁÖÀåÄ¡ ¹øÈ£¸¦ ºÎ¿©ÇÑ´Ù´Â °Í°úµµ °°Àº Àǹ̴Ù. 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 tableÀÇ Æ÷ÀÎÅÍ´Ù. À½¼ö¸¦ ¸®ÅÏ ÇÒ °æ¿ì ÀåÄ¡ µå¶óÀ̹ö µî·Ï¿¡ ½ÇÆÐÇÑ °ÍÀÌ´Ù. ºÎÀåÄ¡ ¹øÈ£¸¦ register_chrdev()¿¡ ³Ñ±âÁö ¾Ê´Â´Ù´Â °Í¿¡ À¯ÀÇÇÏÀÚ. Ä¿³ÎÀº ºÎÀåÄ¡ ¹øÈ£¿¡ ÀüÇô ½Å°æ¾²Áö ¾Ê±â ¶§¹®ÀÌ´Ù. ¿ì¸®ÀÇ µå¶óÀ̹ö¸¸ ±× ¹øÈ£¸¦ »ç¿ëÇÑ´Ù.
ÀÌÁ¦ ¾î¶»°Ô ÀÌ¹Ì »ç¿ëÁßÀÎ ¹øÈ£¸¦ °¡·ÎäÁö ¾Ê°í ÁÖÀåÄ¡ ¹øÈ£¸¦ ¾ò¾î¿À´À³Ä´Â »ý°¢ÀÌ µç´Ù. °¡Àå ½¬¿î ¹æ¹ýÀº Documentation/devices.txt¸¦ º¸°í »ç¿ëÇÏÁö ¾Ê´Â °ÍÀ» ¼±ÅÃÇÏ´Â °ÍÀÌ´Ù. ±×·¯³ª ÀÌ ¹øÈ£°¡ ³ªÁß¿¡ »ç¿ëµÉ ¼ö ÀÖÀ¸¹Ç·Î ÁÁÀº ¹æ¹ýÀº ¾Æ´Ï´Ù. ÇØ°áÃ¥Àº Ä¿³Î¿¡°Ô µ¿ÀûÀ¸·Î ÁÖÀåÄ¡ ¹øÈ£¸¦ ÇÒ´çÇØ ÁÙ °ÍÀ» ¿äûÇÏ´Â °ÍÀÌ´Ù.
register_chrdev()¿¡ ÁÖÀåÄ¡ ¹øÈ£ 0À¸·Î ³Ñ±â¸é, µ¿ÀûÀ¸·Î ÇÒ´çµÈ ÁÖÀåÄ¡ ¹øÈ£¸¦ ¸®ÅÏ ÇØÁØ´Ù. ÁÖÀåÄ¡ ¹øÈ£¸¦ ¾Ë ¼ö ¾ø±â ¶§¹®¿¡ ¹Ì¸® µð¹ÙÀ̽º ÆÄÀÏÀ» ¸¸µé ¼ö ¾ø´Ù´Â ´ÜÁ¡ÀÌ ÀÖ´Ù. ¸î °¡Áö ÇØ°á Ã¥ÀÌ ÀÖ´Ù. ¿ì¼±, µå¶óÀ̹ö°¡ Àڽſ¡°Ô ÇÒ´çµÈ ÁÖÀåÄ¡ ¹øÈ£¸¦ Ãâ·ÂÇÏ°í ¼öÀÛ¾÷À¸·Î ±× ÀåÄ¡ ÆÄÀÏÀ» ¸¸µå´Â °ÍÀÌ´Ù. ´ÙÀ½À¸·Î, /proc/devices¿¡ »õ·Î µî·ÏµÈ ÀåÄ¡°¡ ÀÖÀ» °ÍÀÌ´Ù. ¿ì¸®´Â Á÷Á¢ µð¹ÙÀ̽º ÆÄÀÏÀ» ¸¸µé´øÁö ȤÀº ÆÄÀÏÀ» ÀÐ¾î µé¿© µð¹ÙÀ̽º ÆÄÀÏÀ» ¸¸µå´Â ½© ½ºÅ©¸³Æ® ¸¸µé¸é µÈ´Ù. ¼¼ ¹ø°·Î ÀåÄ¡ µå¶óÀ̹ö¸¦ µî·ÏÇÑ ÈÄmknod¸¦ ÀÌ¿ëÇØ µð¹ÙÀ̽º ÆÄÀÏÀ» ¸¸µé°í cleanup_module()À» È£ÃâÇÑ ÈÄ rmÀ¸·Î »èÁ¦ÇÏ´Â °ÍÀÌ´Ù.
5.1.4. ÀåÄ¡ÀÇ µî·ÏÇØÁ¦ ¶root°¡ ±×·¯°í ½Í´Ù°í Çؼ Ä¿³Î ¸ðµâÀ» rmmodÇÏ°Ô ÇÒ ¼ö´Â ¾ø´Ù. ÇÁ·Î¼¼½º¿¡ ÀÇÇØ ÀåÄ¡ ÆÄÀÏÀ» ¿°í ¸ðµâÀ» Á¦°ÅÇÑ ÈÄ, ÀåÄ¡ ÆÄÀÏÀÇ »ç¿ë½Ãµµ´Â read/writeµî ¿Ã¹Ù¸¥ ÇÔ¼ö°¡ »ç¿ëÇÏ´ø ¸Þ¸ð¸®À§Ä¡¸¦ ´Ù¸¥ °ÍÀ¸·Î ÇÏ¿©±Ý »ç¿ëÇÏ°Ô ÇÒ °ÍÀÌ´Ù. ¸¸ÀÏ ¿îÀÌ ÁÁ´Ù¸é ±×°÷¿¡ ¾Æ¹«·± Äڵ嵵 ·ÎµåµÇÁö ¾ÊÀ» °ÍÀÌ°í ¿¡·¯ ¸Þ½ÃÁö¸¦ ¹ÞÀ» °ÍÀÌ´Ù. ¿ì¸®°¡ ¿îÀÌ ¾ø´Ù¸é °°Àº À§Ä¡·Î ´Ù¸¥ Ä¿³Î ¸ðµâÀÌ ¿Ã¶ó¿Ã °ÍÀÌ°í ±×°ÍÀº Ä¿³Î ³»ÀÇ ´Ù¸¥ ÇÔ¼öÀÇ Áß°£ ¾îµò°¡·Î ½ÇÇàÀ§Ä¡¸¦ ¹Ù²ã ¹ö¸± °ÍÀÌ´Ù. °á°ú´Â ¿¹»óÇÒ ¼ö ¾øÀ¸¸ç ¸Å¿ì ºÎÁ¤ÀûÀÌ´Ù.
ÀϹÝÀûÀ¸·Î ¿ì¸®°¡ ¹«¾ùÀΰ¡ Çã°¡ ÇÏ°í ½ÍÁö ¾Ê´Ù¸é ±× ÀÏÀ» ó¸®ÇÏ´Â ÇÔ¼ö¿¡¼ ¿¡·¯ÄÚµå(À½¼ö)¸¦ ¸®ÅÏÇϵµ·Ï ÇÑ´Ù. void ŸÀÔÀ̱⠶§¹®¿¡ cleanup_module()¿¡¼´Â ÀÌ°ÍÀÌ ºÒ°¡´É ÇÏ´Ù. ±×·¯³ª ¾ó¸¶³ª ¸¹Àº ÇÁ·Î¼¼½º°¡ ±× ¸ðµâÀ» ÀÌ¿ëÇÏ°í ÀÖ´ÂÁö ÃßÀûÇÏ´Â Ä«¿îÅÍ°¡ ÀÖ´Ù. /proc/modulesÆÄÀÏÀÇ ¼¼ ¹ø° ÇʵåÀÇ °ªÀÌ ¹Ù·Î ÀÌ°ÍÀÌ´Ù. ÀÌ ¹øÈ£°¡ 0ÀÌ ¾Æ´Ï¶ó¸é, rmmod´Â ½ÇÆÐÇÑ´Ù. linux/module.c¿¡ Á¤ÀÇ µÇÀÖ´Â sys_delete_module()¿¡ ÀÇÇØ ±× ¼ö°¡ üũµÇ°í ÀÖÀ¸¹Ç·Î cleanup_module()¿¡¼ Ä«¿îÆ® ÇÒ ÇÊ¿ä°¡ ¾ø´Ù. Á÷Á¢ÀûÀ¸·Î Ä«¿îÅ͸¦ »ç¿ëÇÏÁö ¸»ÀÚ, linux/modules.h¿¡ Á¤ÀÇµÈ ¸ÅÅ©·Î°¡ ÀÖ´Ù. ±×°ÍÀº ÀÌ Ä«¿îÅ͸¦ Áõ°¡½ÃÅ°°Å³ª °¨¼Ò½ÃÅ°´Â ÀÏÀ» ÇÑ´Ù.
5.1.5. chardev.c ¶´ÙÀ½ÀÇ ÄÚµå´Âchardev¶ó´Â À̸§ÀÇ ¹®ÀÚ µå¶óÀ̹ö¸¦ ¸¸µå´Â °£´ÜÇÑ ¿¹Á¦´Ù. ÀåÄ¡ÆÄÀÏÀÇ ³»¿ëÀ» ȸ鿡 Ãâ·Â (ȤÀº ´Ù¸¥ ÇÁ·Î±×·¥À» ÀÌ¿ëÇØ ¿¾î º¼ ¼ö ÀÖ´Ù)ÇÒ ¼ö ÀÖ´Ù. ±×·¯¸é µå¶óÀ̹ö´Â ÆÄÀÏÀÌ ÀÐÇôÁø Ƚ¼ö¸¦ ÆÄÀÏ¿¡ ±â·ÏÇÑ´Ù. echo "hi" > /dev/hello¿Í °°ÀÌ ÆÄÀÏ¿¡ ±â·ÏÇÏ´Â °ÍÀ» Áö¿øÇÏÁö ¾Ê´Â´Ù. ±×·¯³ª ÀÌ·± ½Ãµµ¸¦ °¨ÁöÇØ »ç¿ëÀÚ¿¡°Ô ¾²±â ±â´ÉÀ» Áö¿øÇÏÁö ¾Ê´Â ´Ù´Â °ÍÀ» ¾Ë·Á ÁØ´Ù. ¿ì¸®°¡ ÀÐ¾î ¹öÆÛ¿¡ ±â·ÏÇÏ´Â µ¥ÀÌÅ͸¦ °¡Áö°í ¿ì¸®°¡ ÇÏ´Â ÀÏÀ» º¼ ¼ö ¾ø´Ù°í °ÆÁ¤ÇÏÁö ¸¶¶ó; ¿ì¸®´Â ±×°ÍÀ» °¡Áö°í ¸¹Àº ÀÏÀ» ÇÏÁö ¾Ê´Â´Ù. ´ÜÁö µ¥ÀÌÅ͸¦ ÀÐ¾î¼ ±× µ¥ÀÌÅ͸¦ ¹Þ¾Ò´Ù´Â ¸Þ½ÃÁö¸¸ Ãâ·ÂÇÑ´Ù.
Example 4-1. chardev.c
/* chardev.c: ¾ó¸¶³ª ¸¹ÀÌ µð¹ÙÀ̽º ÆÄÀÏ¿¡ Á¢±ÙÇß´ÂÁö ¾Ë·ÁÁÖ´Â ¸ðµâ */
#if defined(CONFIG_MODVERSIONS) && ! defined(MODVERSIONS) #include <linux/modversions.h> #define MODVERSIONS #endif #include <linux/kernel.h> #include <linux/module.h> #include <linux/fs.h> #include <asm/uaccess.h> /* for put_user */ /* 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" /* /proc/devices¿¡ ³ªÅ¸³ª´Â ÀåÄ¡ À̸§ */ #define BUF_LEN 80 /* ÀåÄ¡·ÎºÎÅÍ ¸Þ½ÃÁöÀÇ ÃÖ´ë ±æÀÌ */ /* Á¤Àû º¯¼ö·Î Àü¿ªº¯¼ö ¼±¾ð */ static int Major; /* ÁÖÀåÄ¡ ¹øÈ£ */ static int Device_Open = 0; /* ÀåÄ¡°¡ ¿·È´Â°¡? Áߺ¹»ç¿ë ¹æÁö */ /* access to the device */ static char msg[BUF_LEN]; /* ¿äûÀÌ ÀÖÀ» ¶§ ÀåÄ¡°¡ º¸³»´Â ¸Þ½ÃÁö */ 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 */ /* "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; MOD_INC_USE_COUNT; return SUCCESS; } /* µð¹ÙÀ̽º ÆÄÀÏÀÌ ´ÝÈú ¶§ È£ÃâµÊ. */ static int device_release(struct inode *inode, struct file *file) { Device_Open --; /* We're now ready for our next caller */ /* »ç¿ë Ä«¿îÆ® °¨¼Ò ȤÀº Çѹø ¿¾îº» ÆÄÀÏÀÌ ¾Æ´Ï¶ó¸é ¸ðµâÀ» Á¦°ÅÇÒ ¼ö ¾øÀ½ */ MOD_DEC_USE_COUNT; return 0; } /* ÀÌ¹Ì ¿¸° ÀåÄ¡ ÆÄÀÏ¿¡¼ ¹«¾ùÀΰ¡ ÀÐÀ¸·Á ÇÒ ¶§ È£Ãâ */ static ssize_t device_read(struct file *filp, char *buffer, /* The buffer to fill with data */ size_t length, /* The length of the buffer */ loff_t *offset) /* Our offset in the file */ { /* ¹öÆÛ¿¡ ½ÇÁ¦ ¾²¿©Áø ¹ÙÀÌÆ® ¼ö */ int bytes_read = 0; /* ¸Þ½ÃÁöÀÇ ³¡¿¡ ¸Þ½ÃÁöÀÇ ³¡ÀÓÀ» ¾Ë¸®±â À§ÇØ 0¸®ÅÏ */ if (*msg_Ptr == 0) return 0; /* ¹öÆÛ¿¡ ½ÇÁ¦ µ¥ÀÌÅ͸¦ ÀÔ·Â */ while (length && *msg_Ptr) { /* ¹öÆÛ´Â Ä¿³Î ¼¼±×¸ÕÆ®°¡ ¾Æ´Ï°í »ç¿ëÀÚ ¼¼±×¸ÕÆ®´Ù * ÇÒ´çÀº ÀÏ¾î ³ªÁö ¾Ê´Â´Ù. Ä¿³Î µ¥ÀÌÅÍ¿µ¿ª¿¡¼ »ç¿ëÀÚ ¿µ¿ªÀ¸·Î * µ¥ÀÌÅ͸¦ º¹»çÇÏ´Â put_user() »ç¿ë */ put_user(*(msg_Ptr++), buffer++); length--; bytes_read++; } /* ÀÐÇôÁø µ¥ÀÌÅÍÀÇ ¹ÙÀÌÆ® ¼ö¸¦ ¹öÆÛ¿¡ ±â·Ï */ 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; } 5.1.6. ¿©·¯ Ä¿³Î ¹öÀüÀ» À§ÇÑ ¸ðµâ ÀÛ¼º ¶Ä¿³Î°ú ÇÁ·Î¼¼½º »çÀÌÀÇ ÁÖ¿äÇÑ ÀÎÅÍÆäÀ̽ºÀÎ ½Ã½ºÅÛ ÄÝÀº ÀϹÝÀûÀ¸·Î ¹öÀüÀ» ÀÏÄ¡½ÃÄÑ »ç¿ëÇÑ´Ù. »õ ¹öÀüÀÇ ½Ã½ºÅÛ ÄÝÀÌ Ãß°¡µÇ´õ¶óµµ ±¸ ¹öÀüÀÇ ½Ã½ºÅÛ ÄÝÀº ¿©ÀüÈ÷ µ¿ÀÛÇÑ´Ù. ÀÌ°ÍÀº ±¸ ¹öÀü°úÀÇ °øÁ¸À» À§ÇØ ÇÊ¿äÇÏ´Ù. –»õ ¹öÀüÀÇ Ä¿³ÎÀº ÀϹÝÀûÀÎ ÇÁ·Î¼¼½º¸¦ ÁßÁö½ÃÅ°·Á ÇÏÁö ¾Ê´Â´Ù. ´ëºÎºÐÀÇ °æ¿ì, ÀåÄ¡ ÆÄÀÏÀº ±×´ë·Î ³²¾ÆÀÖ´Ù. On the other hand¹Ý¸é¿¡ , Ä¿³Î ³»ºÎÀÇ ÀÎÅÍÆäÀ̽º´Â ¹öÀü¸¶´Ù ¹Ù²ï´Ù.
¸®´ª½º Ä¿³ÎÀº ¾ÈÁ¤¹öÀü°ú (n.$<$¦¼ö$>$.m) °³¹ß¹öÀüÀ¸·Î (n.$<$Ȧ¼ö$>$.m) ³ª´¶´Ù. °³¹ß ¹öÀüÀº ´ÙÀ½ ¹öÀü¿¡¼ ´Ù½Ã ±¸ÇöÇØ¾ß ÇѴٰųª ¿À·ù·Î Ãë±ÞµÉ ¼öµµ ÀÖ´Â °ÍÀ» ³»Æ÷ÇÑ ¸ðµç Âü½ÅÇÑ ¾ÆÀ̵ð¾î¸¦ Æ÷ÇÔÇÏ°í ÀÖ´Ù. °á°úÀûÀ¸·Î, ÀÌ·± °³¹ß¹öÀüÀÇ ÀÎÅÍÆäÀ̽º´Â ½Å·ÚÇÒ ¼ö ¾ø´Ù (³»°¡ ÀÌ ±Û¿¡¼ ±×°ÍµéÀ» ´Ù·çÁö ¾Ê´Â ÀÌÀ¯À̱⵵ ÇÏ´Ù. ±×°ÍÀº °íµÈ ÀÏÀÌ°í ¹Ù²î±âµµ »¡¸® ¹Ù²ï´Ù.). ¹Ý¸é¿¡ ¾ÈÁ¤¹öÀü¿¡¼, ¹ö±× ¼öÁ¤ ¿©ºÎ¿Í °ü°è¾øÀÌ °°Àº ÀÎÅÍÆäÀ̽º¸¦ ±â´ëÇÒ ¼ö ÀÖ´Ù.
¼·Î ´Ù¸¥ ¹öÀüÀÇ Ä¿³Î¿¡´Â ´Ù¸¥ Â÷ÀÌÁ¡µéÀÌ ÀÖ´Ù. ¸¸ÀÏ ¿©·¯ ¹öÀüÀÇ Ä¿³ÎÀ» Áö¿øÇÏ·Á ÇÑ´Ù¸é, Á¶°Ç ÁöÇâÀûÀÎ ÄÚµå ÄÄÆÄÀÏ ¹æ½ÄÀÌ ÇÊ¿äÇÔÀ» ¾Ë°Ô µÉ °ÍÀÌ´Ù.. LINUX_VERSION_CODE ¿Í KERNEL_VERSION¸¦ ºñ±³ÇÏ´Â ¹æ¹ý. Ä¿³ÎÀÇ a.b.c¹öÀü¿¡¼, ¸ÅÅ©·ÎÀÇ °ªÀº ÀÌ´Ù. Ä¿³Î2.0.35ÀÌÀü ¿¡´Â ÀÌ ¸ÅÅ©·Î°¡ ¾ø´Ù´Â °ÍÀ» ¾Ë¾ÆµÎÀÚ. ±¸½Ä Ä¿³ÎÀ» Áö¿øÇÏ´Â ¸ðµâÀ» ÀÛ¼ºÇÏ°íÀÚ ÇÑ´Ù¸é, ´ÙÀ½°ú °°ÀÌ Á¤ÀÇ ÇØ¾ß ÇÑ´Ù.
Example 4-2. some title
#if LINUX_KERNEL_VERSION >= KERNEL_VERSION(2,2,0)
#define KERNEL_VERSION(a,b,c) ((a)*65536+(b)*256+(c)) #endif ¹°·Ð ÀÌ·± ¸ÅÅ©·Î°¡ Àֱ⠶§¹®¿¡, ´ç½ÅÀº ¸ÅÅ©·ÎÀÇ Á¸Àç¿©ºÎ¸¦ Å×½ºÆ®Çϱâ À§ÇØ Ä¿³Î ¹öÀüÀ» Å×½ºÆ® ÇÏ´Â °Íº¸´Ù #ifndef KERNEL_ VERSION À» »ç¿ëÇÏ´Â °ÍÀÌ ÁÁÀ» °ÍÀÌ´Ù.
6.1. /proc File System ¶¸®´ª½º¿¡´Â Ä¿³Î°ú Ä¿³Î ¸ðµâÀÌ ÇÁ·Î¼¼½º·Î Á¤º¸¸¦ º¸³»´Â Ãß°¡ÀûÀÎ ¹æ¹ýÀÌ ÀÖ´Ù. /procÆÄÀÏ ½Ã½ºÅÛÀÌ ±×°ÍÀÌ´Ù. ¿ø·¡ ÀÌ°ÍÀº ÇÁ·Î¼¼½º¿¡ °üÇÑ Á¤º¸¿¡ ½±°Ô Á¢±ÙÇϵµ·Ï ¼³°èµÈ °ÍÀÌ´Ù(À̸§À» º¸¶ó.). ¸ðµâÀÇ ¸®½ºÆ®¸¦ °¡Áö°í ÀÖ´Â /proc/modules, ±×¸®°í ¸Þ¸ð¸® »ç¿ë·®À» º¸¿©ÁÖ´Â /proc/meminfoµî°ú °°ÀÌ Ä¿³ÎÀÌ °ü½ÉÀ» °®´Â °Íµé¿¡ »ó¿ëµÈ´Ù.
/procÆÄÀÏ ½Ã½ºÅÛÀ» »ç¿ëÇÏ´Â ¹æ¹ýÀº µð¹ÙÀ̽º µå¶óÀ̹ö¸¦ ÀÌ¿ëÇÏ´Â ¹æ¹ý°ú ¸Å¿ì À¯»çÇÏ´Ù. ¿©·¯ºÐÀº ÇÔ¼öÀÇ Çڵ鷯 Æ÷ÀÎÅ͸¦ Æ÷ÇÔÇØ /procÆÄÀÏ¿¡ ÇÊ¿äÇÑ ¸ðµç Á¤º¸¸¦ °¡Áö°í ±¸Á¶Ã¼¸¦ »ý¼ºÇÑ´Ù.( ¿ì¸®ÀÇ °æ¿ì ÇÑ°¡Áö Á¤º¸, ´©±º°¡ /proc ÆÄÀϷκÎÅÍ ¹«¾ùÀΰ¡ ÀÐÀ¸·Á ½ÃµµÇÒ ¶§ ±×°ÍÀÌ È£ÃâµÈ´Ù.). ±×·± ÈÄ Ä¿³Î¿¡ init_module()ÀÌ ±× ±¸Á¶Ã¼¸¦ Ä¿³Î¿¡ µî·ÏÇÏ°í cleanup_moduleÀÌ µî·ÏÀ» ÇØÁ¦ÇÑ´Ù.
¿ì¸®°¡ ¿ì¸®ÀÇ ÆÄÀÏÀÌ ÀÌ¿ëÇÒ inode ¹øÈ£¸¦ °áÁ¤Çϱ⸦ ¿øÇÏÁö ¾Ê°í Ä¿³ÎÀÌ °áÁ¤ÇÏ°Ô Çؼ ½Ã½ºÅÛ ´Ù¿îÀ» ¹æÁöÇϱ⠿øÇϱ⠶§¹®¿¡ ¿ì¸®´Â proc_register_dynamic()1ÇÔ¼ö¸¦ »ç¿ëÇÑ´Ù. ÀϹÝÀûÀÎ ÆÄÀÏÀº ¸Þ¸ð¸®¿¡ Á¸ÀçÇϱ⺸´Ù´Â µð½ºÅ©¿¡ Á¸ÀçÇÑ´Ù.(±×°ÍÀÌ /procÀÌ´Ù.), ¶ÇÇÑ ±×·± °æ¿ì ÆÄÀÏÀÇ À妽º ³ëµå(index-node, inode´Â ¾à¾î´Ù)°¡ À§Ä¡ÇÑ µð½ºÅ©¸¦ inode¹øÈ£°¡ Áö½ÃÇÑ´Ù. inode±¸Á¶Ã¼´Â ÆÄÀÏ¿¡ ´ëÇÑ Á¤º¸¸¦ ´ã°í ÀÖ´Ù, ¿¹¸¦ µé¾î ÆÄÀÏÀÇ Æ۹̼Ç, µð½ºÅ© ¾îµð¼ ÆÄÀÏÀÇ µ¥ÀÌÅ͸¦ ãÀ» ¼ö Àִ°¡ µîµî.
ÆÄÀÏÀÌ ¿¸®°Å³ª ´ÝÈú ¶§ ¿ì¸®°¡ È£ÃâÇÏÁö ¾Ê¾Ò±â ¶§¹®¿¡ , ¸ðµâ ³»ºÎ¿¡¼ MOD_INC_USE_COUNT¿Í MOD_DEC_USE_COUNT¿¡ Á¢±ÙÇÒ ¹æ¹ýÀÌ ¾ø´Ù. ¶ÇÇÑ ÆÄÀÏÀÌ ¿¸° »óÅ¿¡¼ ¸ðµâÀÌ Á¦°ÅµÉ ¶§ »ý±â´Â ¹®Á¦¸¦ ÇÇÇÒ ¹æ¹ýÀÌ ¾ø´Ù. ´ÙÀ½ Àå¿¡¼ ¿ì¸®´Â ´õ º¹ÀâÇÑ ±¸ÇöÀ» º»´Ù, ±×·¯³ª ±×°ÍÀº /procÆÄÀÏÀ» ´Ù·ç´Âµ¥ ÀÖ¾î ´õ À¯¿¬ÇÑ ¹æ¹ýÀ» Á¦½ÃÇØÁÙ °ÍÀÌ´Ù. ±×¸®°í ±×°ÍÀº ¹®Á¦¿¡ ºÀÂøÇÏÁö ¾Ê°Ô ÇØÁֱ⵵ ÇÑ´Ù.
Example 5-1. procfs.c
/* procfs.c - create a "file" in /proc */
#include <linux/kernel.h> /* Ä¿³Î ÀÛ¾÷ */ #include <linux/module.h> /* ¸ðµâ ÀÛ¾÷ */ /* Deal with CONFIG_MODVERSIONS */ #if CONFIG_MODVERSIONS==1 #define MODVERSIONS #include <linux/modversions.h> #endif /* proc fs¸¦ ´Ù·é´Ù */ #include <linux/proc_fs.h> /* 2.2.3 ¹öÀü ÀÌÀü¿¡´Â ´ÙÀ½ÀÇ ¸ÅÅ©·Î°¡ ¾ø´Ù. ÇÊ¿äÇÏ´Ù¸é ¿©±â¼ Á¤ÀÇ ÇÑ´Ù.*/ #ifndef KERNEL_VERSION#define KERNEL_VERSION(a,b,c) ((a)*65536+(b)*256+(c)) #endif /* proc fs¿¡ µ¥ÀÌÅÍ Àü´Þ. Argument ========= 1. µ¥ÀÌÅÍ°¡ »ðÀԵǴ ¹öÆÛ, ¸¸ÀÏ »ç¿ëÇϱ⠿øÇÑ´Ù¸é 2. ¹®ÀÚ¿¿¡ ´ëÇÑ Æ÷ÀÎÅÍ, ¸¸ÀÏ Ä¿³ÎÀÌ ¹öÆÛ¸¦ ÇÒ´çÇϱ⠿øÇÏÁö ¾Ê´Â °æ¿ì »ç¿ë 3. ÆÄÀÏ¿¡¼ ÇöÀç À§Ä¡ 4. ù ÀÎÀÚ ¹öÆÛÀÇ Å©±â 5. 0(¹Ì·¡ÀÇ »ç¿ëÀ» À§ÇØ?). Usage and Return Value ====================== ¸¸ÀÏ ÀڽŸ¸ÀÇ ¹öÆÛ¸¦ ¿øÇÑ´Ù¸é ³»°¡ ÇÑ °Íó·³ µÎ¹ø ° ÀÎÀÚ¿¡ ³Ö°í ¹öÆÛ¿¡¼ »ç¿ëÇÑ ¹ÙÀÌÆ® ¼ö¸¦ ¸®ÅÏÇÏ¶ó ¸®ÅÏ °ªÀÌ NULLÀΰÍÀº ´õ ÀÌ»óÀÇ Á¤º¸°¡ ¾øÀ½À» ÀǹÌÇÑ´Ù(end of file). ¶ÇÇÑ À½¼öÀÎ °æ¿ì ¿¡·¯ »óȲÀÌ´Ù. For More Information ==================== The way I discovered what to do with this function ³»°¡ ÀÌ ÇÔ¼ö¿¡¼ ¹«¾ùÀΰ¡¸¦ ¹ß°ßÇÑ ¹æ¹ýÀº ¹®¼¸¦ Àд °ÍÀÌ ¾Æ´Ï°í, »ç¿ëµÇ´Â Äڵ带 Àд °ÍÀ̾ú´Ù. proc_dir_entry±¸Á¶Ã¼ÀÇ get_infoÇʵ带 ¾îµð´Ù ¾²´Â°¡¸¦ »ìÆìºÃ´Ù. ¶ÇÇÑ /fs/proc/array.c ÆÄÀÏÀÌ »ç¿ëµÇ´Â °ÍÀ» »ìÆì º» °ÍÀÌ´Ù. If something is unknown about the kernel, this is ¹«¾ð°¡ Ä¿³Î¿¡¼ Àß ¸ð¸£´Â ºÎºÐÀÌ ÀÖ´Ù¸é ÀÌ·± ¹æ½ÄÀÌ ÀϹÝÀûÀ¸·Î ÇàÇØÁø´Ù. ¸®´ª½º¿¡¼ ¿ì¸®´Â Ä¿³Î Äڵ带 ¾òÀ» ¼ö ÀÖ´Ù´Â °ÍÀº ´ë´ÜÇÑ ÀåÁ¡ÀÌ´Ù. È°¿ëÇ϶ó. */ int procfile_read(char *buffer, char **buffer_location, off_t offset, int buffer_length, int zero) { int len; /* ½ÇÁ¦ »ç¿ëµÇ´Â ¹ÙÀÌÆ® ¼ö */ /* ¿ì¸®°¡ ÀÌ ÇÔ¼ö¸¦ ³ª°¥ ¶§µµ ÀÌ ½ºÅ×ƽ º¯¼öÀ̱⠶§¹®¿¡ ¸Þ¸ð¸®¿¡ ³²°Ü Áø´Ù. */ static char my_buffer[80]; static int count = 1; /* ¿ì¸®(Á÷¿ª)´Â Çѹø¿¡ ¸ðµç Á¤º¸¸¦ Áֱ⠶§¹®¿¡ À¯Àú(?Á÷¿ª)°¡ Ãß°¡ÀûÀÎ Á¤º¸¸¦ ¿ä±¸ÇÒ ¶§ ¿ì¸®ÀÇ ´ë´äÀº NO´Ù. * Ç¥ÁØ ¶óÀ̺귯¸® ÇÔ¼ö´Â Ä¿³ÎÀÌ ´õ ÀÌ»ó ÁÙ Á¤º¸°¡ ¾ø´Ù°í ¸»ÇÒ ¶§±îÁö, ȤÀº Ç¥ÁØ ¶óÀ̺귯¸® ÇÔ¼öÀÇ ¹öÆÛ°¡ ´Ù Âû ¶§±îÁö * read ½Ã½ºÅÛ ÄÝÀ» Çϱ⠶§ ¹®¿¡ Áß¿äÇÏ´Ù. */ if (offset > 0) return 0; /* Fill the buffer and get its length */ len = sprintf(my_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++; /* ÇÔ¼ö¿¡ ¹öÆÛÀÇ À§Ä¡¸¦ ¾Ë¸°´Ù. */ *buffer_location = my_buffer; /* Return the length */ return len; } struct proc_dir_entry Our_Proc_File = {0, /* Inode ¹øÈ£ –¿©±â¼´Â ¹«½ÃÇÑ´Ù. ÀÌ°ÍÀº proc_register[_dynamic]¿¡ ÀÇÇØ Ã¤¿öÁø´Ù. */ 4, /* ÆÄÀÏÀÇ À̸§ ±æÀÌ */ "test", /* ÆÄÀÏÀ̸§ */ S_IFREG | S_IRUGO, /* File mode – ÀÏ¹Ý ÆÄÀÏ, ¼ÒÀ¯ÀÚ, ±×·ì, ¸ðµç »ç¶÷µéÀÌ ÀÖÀ» ¼ö ÀÖ´Ù.*/ 1, /* ÆÄÀÏÀÌ Âü°íÇÏ´Â µð·ºÅ丮ÀÇ ¸µÅ© °³¼ö*/ 0, 0, /* uid, gid ·çÆ®¿¡°Ô ±ÇÇÑÀ» ÁØ´Ù.*/ 80, /* ls¿¡ ÀÇÇØ º¸°íµÇ´Â ÆÄÀÏÀÇ Å©±â. */ NULL, /* link, removeµî inode»ó¿¡ ÇàÇØÁö´Â ÇÔ¼ö- ¿ì¸®´Â ¾Æ¹«°Íµµ Áö¿øÇÏÁö ¾Ê´Â´Ù. */ procfile_read, /* Àбâ ÇÔ¼ö, ¹«¾ùÀΰ¡¸¦ ÀÐÀ¸·Á ÇÒ ¶§ È£ÃâµÇ´Â ÇÔ¼ö */ NULL /* Æ۹̼Ç, ¼ÒÀ¯±Ç µîÀ» ´Ù·ç´Â inode¸¦ ä¿ì´Â ÇÔ¼öÀÇ Æ÷ÀÎÅÍ */ }; /* Initialize the module - register the proc file */ int init_module() { /* proc_register[_dynamic]ÀÌ ¼º°øÇÏ¸é ¼º°ø, ¾Æ´Ï¸é ½ÇÆÐ */ #if LINUX_VERSION_CODE > KERNEL_VERSION(2,2,0) /* ±¸Á¶Ã¼¿¡¼ ±× °ªÀÌ 0À̸é 2.2¹öÀü¿¡¼´Â proc_register()ÇÔ¼ö°¡ inode¹øÈ£¸¦ µ¿ÀûÀ¸·Î ÇÒ´çÇÑ´Ù. * proc_register_dynamic()ÇÔ¼ö°¡ ÇÊ¿ä¾ø°Ô µÈ´Ù. */ return proc_register(&proc_root, &Our_Proc_File); #else return proc_register_dynamic(&proc_root, &Our_Proc_File); #endif /* proc_root´Â procÆÄÀÏ ½Ã½ºÅÛÀÇ ·çÆ®(/proc) * ¿ì¸®°¡ ÆÄÀÏÀ» À§Ä¡½ÃÅ°±â ¿øÇÏ´Â À§Ä¡´Ù. */ } /* Cleanup - unregister our file from /proc */ void cleanup_module() { proc_unregister(&proc_root, Our_Proc_File.low_ino); } 7.1. ÀÔ·ÂÀ» À§ÇÑ /procÀÇ »ç¿ë ¶Áö±Ý±îÁö ¿ì¸®´Â Ä¿³Î ¸ðµâ·ÎºÎÅÍ Ãâ·ÂÀ» ¾ò´Â µÎ °¡Áö ¹æ¹ýÀ» ¾Ë¾Æ º¸¾Ò´Ù. ¿ì¸®´Â ÀåÄ¡ µå¶óÀ̹ö¿Í mknod¸¦ µî·ÏÇϰųª /proc ÆÄÀÏÀ» »ý¼ºÇÒ ¼ö ÀÖ´Ù. ÀÌ°ÍÀº Ä¿³Î ¸ðµâ·Î ÇÏ¿©±Ý ¿ì¸®¿¡°Ô ¹«¾ùÀΰ¡¸¦ Àü´ÞÇÒ ¼ö ÀÖµµ·Ï ÇØÁØ´Ù. ±× ¹Ý´ëÀÇ °æ¿ì°¡ ºÒ°¡´ÉÇÏ´Ù´Â °ÍÀÌ ¹®Á¦°¡ µÈ´Ù. ¿ì¼± Ä¿³Î ¸ðµâ¿¡ µ¥ÀÌÅ͸¦ ÀÔ·ÂÇÏ´Â °ÍÀº /proc ÆÄÀÏ¿¡ µ¥ÀÌÅ͸¦ ¾²´Â ¹æ¹ýÀ» ÅÃÇÑ´Ù.
/procÆÄÀÏ ½Ã½ºÅÛÀº Ä¿³ÎÀÌ ÇÁ·Î¼¼½ºÀÇ »óŸ¦ º¸°íÇÒ ¼ö ÀÖµµ·Ï ÇÑ °ÍÀ̱⠶§¹®¿¡ , ÀԷ¿¡ ´ëÇÑ Æ¯º°ÇÑ ¹è·Á´Â ¾ø´Ù. proc_dir_entry ±¸Á¶Ã¼¿¡´Â Ãâ·Â ÇÔ¼ö¿Í °°Àº ¹æ½ÄÀÇ ÀÔ·Â ÇÔ¼ö¿¡ ´ëÇÑ Æ÷ÀÎÅÍ°¡ ¾ø´Ù. /procÆÄÀÏ¿¡ ¾²±â¸¦ ÇÏ´Â ´ë½Å, Ç¥ÁØ ÆÄÀÏ ½Ã½ºÅÛ ¸ÞÄ¿´ÏÁòÀ» »ç¿ëÇÒ ÇÊ¿ä°¡ ÀÖ´Ù.
¸®´ª½º¿¡´Â ÆÄÀÏ ½Ã½ºÅÛ µî·ÏÀ» À§ÇÑ Ç¥ÁØ ¸ÞÄ¿´ÏÁòÀÌ ÀÖ´Ù. ¸ðµç ÆÄÀÏ ½Ã½ºÅÛÀº inode¿Í file operationÀ» ´Ù·ç±â À§ÇÑ °íÀ¯ÇÑ ÇÔ¼ö¸¦ °¡Áö°í ÀÖ¾î¾ß Çϱ⠶§¹®¿¡ ÀÌ ¸ðµç ÇÔ¼öÀÇ Æ÷ÀÎÅ͸¦ °¡Áö°í ÀÖ´Â inode_operations ¶ó´Â ±¸Á¶Ã¼°¡ ÀÖÀ¸¸ç, ±×¸®°í ±×°ÍÀº file_operations±¸Á¶Ã¼¸¦ Áö½ÃÇÏ´Â Æ÷ÀÎÅ͸¦ Æ÷ÇÔÇÏ°í ÀÖ´Ù. »õ ÆÄÀÏÀ» µî·ÏÇÒ ¶§¸¶´Ù, /proc¿¡¼ ±×°Í¿¡ Á¢±ÙÇϱâ À§ÇØ ¾î´À inode_operations ±¸Á¶Ã¼¸¦ »ç¿ëÇÒ °ÍÀÎÁö °áÁ¤ÇÑ´Ù. ¿ì¸®°¡ »ç¿ëÇÒ module_input(), module_output()ÇÔ¼ö¸¦ Áö½ÃÇÏ´Â Æ÷ÀÎÅ͸¦ Æ÷ÇÔÇÑ file_operation ±¸Á¶Ã¼¸¦ Áö½ÃÇÏ´Â Æ÷ÀÎÅ͸¦ Æ÷ÇÔÇÑ inode_operations ±¸Á¶Ã¼, ÀÌ°ÍÀÌ ¿ì¸®°¡ »ç¿ëÇÏ´Â ¸ÞÄ¿´ÏÁòÀÌ´Ù.
Àбâ¿Í ¾²±â¸¦ À§ÇÑ Ç¥ÁØ ·Ñ ¼ÂÀÌ Ä¿³Î¿¡¼´Â ¹Ý´ë·Î ÁöÁ¤µÅÀÖ´Ù´Â °ÍÀ» ¸í½ÉÇÏÀÚ. Àбâ ÇÔ¼ö´Â Ãâ·ÂÀ» À§ÇØ, ¹Ý´ë·Î ¾²±âÇÔ¼ö´Â ÀÔ·ÂÀ» À§ÇØ »ç¿ë µÈ´Ù. Àϱâ¿Í ¾²±â´Â »ç¿ëÀÚÀÇ °üÁ¡¿¡¼ º» °ÍÀ̱⠶§¹®ÀÌ´Ù. --- ¸¸ÀÏ ÇÁ·Î¼¼½º°¡ Ä¿³Î¿¡¼ ¹«¾ð°¡ Àд´ٸé Ä¿³ÎÀº ±×°ÍÀ» Ãâ·ÂÇØ ÁÖ¾î¾ß ÇÑ´Ù. ±×¸®°í ÇÁ·Î¼¼½º°¡ Ä¿³Î¿¡ ¹«¾ð°¡¸¦ ¾´´Ù¸é Ä¿³ÎÀº ±×°ÍÀ» ÀÔ·ÂÀ¸·Î ¹Þ¾Æ µé¿©¾ß ÇÑ´Ù.
Èï¹Ì ÀÖ´Â ¶Ç ´Ù¸¥ °ÍÀº module_permissions() ÇÔ¼ö´Ù. ÇÁ·Î¼¼½º°¡ /proc ÆÄÀÏ¿¡ ¹«¾ð°¡¸¦ ÇÏ·Á°í ÇÒ ¶§¸¶´Ù, ÀÌ ÇÔ¼ö´Â È£Ã⠵ȴÙ. ±×¸®°í ÀÌ ÇÔ¼ö´Â ÀÌ Á¢±ÙÀ» Çã¿ëÇÒ °ÍÀΰ¡ ¸» °ÍÀΰ¡¸¦ °áÁ¤ÇÏ°Ô µÈ´Ù. ´çÀåÀº ÀÌ°ÍÀÌ ÇöÀç »ç¿ëÀÚÀÇ uid¿Í ÇàÀ§(operation) ÀÚü¿¡¸¸ ±Ù°Å ÇÏÁö¸¸, (±×¸®°í ÀÌ°ÍÀº ÇöÀç ½ÇÇàµÇ´Â ÇÁ·Î¼¼½ºÀÇ Á¤º¸¸¦ ´ã°í ÀÖ´Â ±¸Á¶Ã¼ÀÇ Æ÷ÀÎÅÍ¿¡¼ ã¾Æ Áú ¼ö ÀÖ´Â °Íµé) ÀÌ°ÍÀº ÇÁ·Î¼¼½º°¡ ¹«¾ùÀ» ÇÏ´Â °ÍÀΰ¡, ÀÛ¾÷ ½Ã°¢, ¸¶Áö¸·À¸·Î ¹«¾ùÀ» ÀÔ·Â ¹Þ¾Ò´Â°¡ µî, ¿ì¶ó±â ¿øÇÏ´Â ¾î¶² °Í¿¡ ±Ù°ÅÇÒ ¼öµµ ÀÖ´Ù.
ÀÎÅÚ ¾ÆÅ°ÅØÃÄ¿¡¼(¹°·Ð ´Ù¸¥ ÇÁ·Î¼¼¼ ÇÏ¿¡¼´Â ´Þ¶óÁú ¼öµµ ÀÖÁö¸¸) put_user() ¸ÅÅ©·Î¿Í get_user()¸ÅÅ©·Î¸¦ »ç¿ëÇÏ´Â ÀÌÀ¯´Â ¸®´ª½ºÀÇ ¸Þ¸ð¸®°¡ ¼¼±×¸ÕÆ® À̱⠶§¹®ÀÌ´Ù. Æ÷ÀÎÅÍ ÀÚü´Â À¯´ÏÅ©ÇÑ ¸Þ¸ð¸® À§Ä¡¸¦ Áö½ÃÇÒ ¼ö ¾ø°í, ¸Þ¸ð¸® ¼¼±×¸ÕÆ® À§Ä¡¸¸ Áö½ÃÇÒ ¼ö ÀÖ´Ù. ¶ÇÇÑ ¾î´À ¸Þ¸ð¸® ¼¼±×¸ÕÆ®¸¦ »ç¿ëÇÒ ¼ö ÀÖ´ÂÁö ¾Ë ÇÊ¿ä°¡ ÀÖ´Ù. Ä¿³ÎÀ» À§ÇÑ ¸Þ¸ð¸® ÇϳªÀÇ ¼¼±×¸ÕÆ®°¡ ÀÖ°í, °¢ ÇÁ·Î¼¼½ºµé¸¶´Ù ÇϳªÀÇ ¼¼±×¸ÕÆ®°¡ Á¸ÀçÇÑ´Ù.
ÇÁ·Î¼¼½º ÀÚ½ÅÀÇ ¸Þ¸ð¸® ¼¼±×¸ÕÆ®¿¡¸¸ Á¢±ÙÀÌ °¡´ÉÇÏ´Ù. ±×·¡¼ ÀϹÝÀûÀÎ ÇÁ·Î±×·¥ÀÌ ÇÁ·Î¼¼½º·Î¼ ½ÇÇàµÉ ¶§ ¼¼±×¸ÕÆ®¿¡ °üÇØ ½Å°æ ¾²Áö ¾Ê¾Æµµ µÈ´Ù. Ä¿³Î ¸ðµâÀ» ÀÛ¼ºÇÒ ¶§, ÀϹÝÀûÀ¸·Î ½Ã½ºÅÛ¿¡ ÀÇÇØ ÀÚµ¿À¸·Î ´Ù·ïÁö´Â Ä¿³Î ¸Þ¸ð¸® ¼¼±×¸ÕÆ®¿¡ Á¢±ÙÇϱ⸦ ¿øÇÑ´Ù. ±×·¯³ª ¸Þ¸Ó¸® ¹öÆÛÀÇ ³»¿ëÀÌ ÇöÀç ½ÇÇà ÁßÀÎ ÇÁ·Î¼¼½º¿Í Ä¿³Î »çÀÌ¿¡¼ Àü´Þ µÇ¾ß ÇÒ ¶§, Ä¿³Î ÇÔ¼ö´Â ÇÁ·Î¼¼½º ¼¼±×¸ÕÆ®¿¡ ÀÖ´Â ¸Þ¸ð¸® Æ÷ÀÎÅ͸¦ ¹Þ°Ô µÈ´Ù. put_user() ¸ÅÅ©·Î¿Í get_user() ¸ÅÅ©·Î°¡ ±× ¸Þ¸ð¸®¿¡ Á¢±Ù °¡´ÉÄÉ ÇØÁØ´Ù.
Example 6-1. procfs.c
/* procfs.c - create a "file" in /proc, which allows both input and output. */
#include <linux/kernel.h> /* We're doing kernel work */ #include <linux/module.h> /* Specifically, a module */ /* Necessary because we use proc fs */ #include <linux/proc_fs.h> /* In 2.2.3 /usr/include/linux/version.h includes a * macro for this, but 2.0.35 doesn't - so I add it * here if necessary. */ #ifndef KERNEL_VERSION#define KERNEL_VERSION(a,b,c) ((a)*65536+(b)*256+(c)) #endif #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0) #include <asm/uaccess.h> /* for get_user and put_user */ #endif /* 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]; /* 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 */ #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0) static ssize_t module_output( struct file *file, /* The file read */ char *buf, /* The buffer to put data to (in the * user segment) */ size_t len, /* The length of the buffer */ loff_t *offset) /* Offset in the file - ignore */ #else static int module_output( struct inode *inode, /* The inode read */ struct file *file, /* The file read */ char *buf, /* The buffer to put data to (in the * user segment) */ int len) /* The length of the buffer */ #endif { 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<len && message[i]; i++) put_user(message[i], buf+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" */ } /* This function receives input from the user when the * user writes to the /proc file. */ #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0) 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 */ #else static int module_input( struct inode *inode, /* The file's inode */ struct file *file, /* The file itself */ const char *buf, /* The buffer with the input */ int length) /* The buffer's length */ #endif { 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++) #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0) get_user(Message[i], buf+i); /* In version 2.2 the semantics of get_user changed, * it not longer returns a character, but expects a * variable to fill up as its first argument and a * user segment pointer to fill it from as the its * second. * * The reason for this change is that the version 2.2 * get_user can also read an short or an int. The way * it knows the type of the variable it should read * is by using sizeof, and for that it needs the * variable itself. */ #else Message[i] = get_user(buf+i);#endif Message[i] = '\0'; /* we want a standard, zero * terminated string */ /* We need to return the number of input characters * used */ 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) { /* 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) { MOD_INC_USE_COUNT; return 0; } /* The file is closed - again, interesting only because * of the reference count. */ #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0) int module_close(struct inode *inode, struct file *file) #else void module_close(struct inode *inode, struct file *file) #endif { MOD_DEC_USE_COUNT; #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0) return 0; /* success */ #endif } /* 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 = { NULL, /* lseek */ module_output, /* "read" from the file */ module_input, /* "write" to the file */ NULL, /* readdir */ NULL, /* select */ NULL, /* ioctl */ NULL, /* mmap */ module_open, /* Somebody opened the file */ #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0) NULL, /* flush, added here in version 2.2 */ #endif module_close, /* Somebody closed the file */ /* etc. etc. etc. (they are all given in * /usr/include/linux/fs.h). Since we don't put * anything here, the system will keep the default * data, which in Unix is zeros (NULLs when taken as * pointers). */ }; /* 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 = { &File_Ops_4_Our_Proc_File, NULL, /* create */ NULL, /* lookup */ NULL, /* link */ NULL, /* unlink */ NULL, /* symlink */ NULL, /* mkdir */ NULL, /* rmdir */ NULL, /* mknod */ NULL, /* rename */ NULL, /* readlink */ NULL, /* follow_link */ NULL, /* readpage */ NULL, /* writepage */ NULL, /* bmap */ NULL, /* truncate */ module_permission /* check for permissions */ };/* Directory entry */ static struct proc_dir_entry Our_Proc_File = { 0, /* Inode number - ignore, it will be filled by * proc_register[_dynamic] */ 7, /* Length of the file name */ "rw_test", /* The file name */ S_IFREG | S_IRUGO | S_IWUSR, /* File mode - this is a regular file which * can be read by its owner, its group, and everybody * else. Also, its owner can write to it. * * Actually, this field is just for reference, it's * module_permission that does the actual check. It * could use this field, but in our implementation it * doesn't, for simplicity. */ 1, /* Number of links (directories where the * file is referenced) */ 0, 0, /* The uid and gid for the file - * we give it to root */ 80, /* The size of the file reported by ls. */ &Inode_Ops_4_Our_Proc_File, /* A pointer to the inode structure for * the file, if we need it. In our case we * do, because we need a write function. */ NULL /* The read function for the file. Irrelevant, * because we put it in the inode structure above */ }; /* Module initialization and cleanup ******************* */ /* Initialize the module - register the proc file */ int init_module() { /* Success if proc_register[_dynamic] is a success, * failure otherwise */ #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0) /* In version 2.2, proc_register assign a dynamic * inode number automatically if it is zero in the * structure , so there's no more need for * proc_register_dynamic */ return proc_register(&proc_root, &Our_Proc_File); #else return proc_register_dynamic(&proc_root, &Our_Proc_File); #endif } /* Cleanup - unregister our file from /proc */ void cleanup_module() { proc_unregister(&proc_root, Our_Proc_File.low_ino); } 8.1. Talking to Device Files (writes and IOCTLs) ¶µð¹ÙÀ̽º ÆÄÀÏÀº ¹°¸®Àû ÀåÄ¡¸¦ ³ªÅ¸³»´Â °ÍÀ¸·Î °£ÁֵȴÙ. ´ëºÎºÐÀÇ ¹°¸®Àû ÀåÄ¡µéÀº ÀÔÃâ·ÂÀ» À§ÇØ »ç¿ëµÈ´Ù. ±×·¡¼ Ä¿³Î ¾È¿¡¼ µð¹ÙÀ̽º µå¶óÀ̹ö°¡ ÇÁ·Î¼¼½º·ÎºÎÅÍ µð¹ÙÀ̽º·Î º¸³¾ ¾Æ¿ôDzÀ» ¾ò±â À§ÇØ Æ¯º°ÇÑ ¸ÞÄ¿´ÏÁòÀÌ ÇÊ¿äÇÏ´Ù. ÆÄÀÏ¿¡ ¾²±â¸¦ ÇÏ´Â °Íó·³, ¾Æ¿ôDzÀ» ¾²±â À§ÇØ µð¹ÙÀ̽º ÆÄÀÏÀ» ¿ÀÇ ÇÏ´Â °ÍÀ¸·Î µÈ´Ù. ´ÙÀ½ÀÇ ¿¹¿¡¼ ÀÌ°ÍÀº device_write()ÇÔ¼ö¿¡ ÀÇÇØ ±¸ÇöµÈ´Ù.
ÀÌ°ÍÀ¸·Î Ç×»ó ÃæºÐÇÑ °ÍÀº ¾Æ´Ï´Ù. ¸ðµ©¿¡ ¿¬°áµÈ ½Ã¸®¾ó Æ÷Æ®°¡ ÀÖ´Ù°í »ó»óÇغ¸ÀÚ. (³»Àå ¸ðµ©À̶ó Çصµ CPUÀÇ °üÁ¡¿¡¼ ¸ðµ©¿¡ ½Ã¸®¾ó Æ÷Æ®°¡ ¿¬°áµÈ °ÍÀ¸·Î ±¸ÇöµÈ´Ù. ³Ê¹« Áö³ªÄ¡°Ô ±íÀÌ »ó»óÇÏÁö ¸»ÀÚ). ÇØ¾ß ÇÒ °ÍÀº µð¹ÙÀ̽º ÆÄÀÏÀ» ÀÌ¿ëÇØ ¸ðµ©¿¡ ¹«¾ð°¡(¸ðµ© ¸í·É¾î ȤÀº Àüȼ±À» ÅëÇØ ³ª°¡´Â µ¥ÀÌÅÍ)¸¦ ±â·ÏÇÏ´Â °ÍÀÌ°í, ¸ðµ©À¸·ÎºÎÅÍ ¹«¾ð°¡(¸í·É¿¡ ´ëÇÑ ÀÀ´ä, ȤÀº Àüȼ±À» ÅëÇÑ µ¥ÀÌÅÍ)¸¦ ÀÐ¾î ¿À´Â °ÍÀÌ´Ù. ¿¹¸¦ µé¾î ¾î¶² ¼Óµµ·Ï µ¥ÀÌÅ͸¦ º¸³¾ °ÍÀΰ¡? ¿Í °°Àº Áú¹®Àº ¿©ÀüÈ÷ ³²´Â´Ù.
À¯´Ð½º¿¡¼ Input Output Control ÀÇ ÁØ ¸»ÀÎioctl()À̶ó´Â Ư¼öÇÑ ÇÔ¼ö¸¦ È£ÃâÇÏ´Â °ÍÀÌ ´äÀÌ µÈ´Ù. ¸ðµç µð¹ÙÀ̽ºµå¶óÀ̹ö´Â ÀڽŸ¸ÀÇ ioctl ¸í·ÉÀ» °®À» ¼ö ÀÖ°í, ±×¸®°í ±×°ÍÀº Àб⸦ À§ÇÑ ioctl Ä¿¸Çµå(ÇÁ·Î¼¼½º·ÎºÎÅÍ Ä¿³Î·Î Á¤º¸¸¦ º¸³»´Â )À̰ųª ¾²±â¸¦ À§ÇÑ ioctl Ä¿¸Çµå(ÇÁ·Î¼¼½º·Î Á¤º¸¸¦ µ¹¸®´Â), ȤÀº µÑ ¸ðµÎ, ȤÀº µÑ ¸ðµå ¾Æ´Ï´Ù. ioctlÇÔ¼ö´Â ´ÙÀ½°ú °°Àº ¼¼ °³ÀÇ ÀÎÀÚ¸¦ °¡Áø´Ù. ÇØ´çµÇ´Â µð¹ÙÀ̽º ÆÄÀÏÀÇ µð½ºÅ©¸³ÅÍ, ioctl¹øÈ£, ·ÕÇüÀ¸·Î ¾î¶² ŸÀÔÀ¸·Î´øÁö ÄɽºÆÃÈÄ »ç¿ëÇÒ ¼ö ÀÖ´Â ÀÎÀÚ2
ioctlÀÇ ¹øÈ£´Â ÀåÄ¡ ÁÖ¹øÈ£, ioctlÀÇ Å¸ÀÔ(Àбâ/¾²±â), Ä¿¸Çµå, ÀÎÀÚÀÇ Å¸ÀÔÀ¸·Î ¸¸µé¾î Áø´Ù. ÀÌ ioctl ¹øÈ£´Â Çì´õÆÄÀÏ¿¡ ÀÖ´Â _IO, _IOR, _IOW or _IOWR(À̵éÀº º¸Åë ŸÀÔ¿¡ µû¶ó ´Þ¸® ¾²ÀÓ) ¿Í °°Àº ¸ÅÅ©·Î¿¡ ÀÇÇØ º¸Åë ¸¸µé¾îÁø´Ù. Çì´õ ÆÄÀÏÀº ioctlÀ» »ç¿ëÇÏ´Â ÇÁ·Î±×·¥(Àû´çÇÑ ioctl¸í·ÉÀ» ¸¸µé±â À§ÇØ )À̳ª, Ä¿³Î ¸ðµâ(¸¸µé¾î Áø ioctl¸í·ÉÀ» ÀÌÇØÇϱâ À§ÇØ) ¸ðµÎ¿¡ Æ÷ÇÔµÇ¾ß ÇÑ´Ù. ´ÙÀ½ÀÇ ¿¹¿¡¼, chardev.h°¡ Çì´õ ÆÄÀÏÀÌ°í ±×°ÍÀ» »ç¿ëÇÏ´Â ÇÁ·Î±×·¥Àº ioctl.cÀÌ´Ù.
¸¸ÀÏ ´ç½ÅÀÇ Ä¿³Î ¸ðµâ¿¡¼ ioctlÀ» »ç¿ëÇϱ⠿øÇÑ´Ù¸é, ioctl ¸í·ÉÀ» ÇÒ´çÇÏ´Â °ÍÀÌ °¡Àå ÁÁ´Ù. ±×·¡¼ ¿ì¿¬È÷ ´Ù¸¥ »ç¶÷ÀÇ ioctl Ä¿¸Çµå¸¦ ¹Þ°Ô µÇ°Å³ª, ´Ù¸¥ »ç¶÷ÀÌ ´ç½ÅÀÇ ioctlÄ¿¸Çµå¸¦ ¹Þ¾Æµµ ±×°ÍÀÌ À߸øµÆ´Ù´Â °ÍÀ» ¾Ë°Ô µÈ´Ù. Á»´õ ¸¹Àº Á¤º¸¸¦ À§Çؼ Ä¿³Î¼Ò½ºÀÇ Documentation/ioctl-number.txtÆÄÀÏÀ» Âü°íÇÏ±æ ¹Ù¶õ´Ù.
Example 7-1. chardev.c
/* chardev.c - Create an input/output character device
*/ #include <linux/kernel.h> /* We're doing kernel work */ #include <linux/module.h> /* Specifically, a module */ /* Deal with CONFIG_MODVERSIONS */ #if CONFIG_MODVERSIONS==1 #define MODVERSIONS #include <linux/modversions.h> #endif /* For character devices */ /* The character device definitions are here */ #include <linux/fs.h> /* A wrapper which does next to nothing at * at present, but may help for compatibility * with future versions of Linux */ #include <linux/wrapper.h> /* Our own ioctl numbers */ #include "chardev.h" /* In 2.2.3 /usr/include/linux/version.h includes a * macro for this, but 2.0.35 doesn't - so I add it * here if necessary. */ #ifndef KERNEL_VERSION #define KERNEL_VERSION(a,b,c) ((a)*65536+(b)*256+(c)) #endif #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0) #include <asm/uaccess.h> /* for get_user and put_user */ #endif #define SUCCESS 0 /* Device Declarations ******************************** */ /* The name for our device, as it will appear in * /proc/devices */ #define DEVICE_NAME "char_dev" /* The maximum length of the message for the device */ #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 function 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; /* If this was a process, we would have had to be * more careful here, because one process might have * checked Device_Open right before the other one * tried to increment it. However, we're in the * kernel, so we're protected against context switches. * * This is NOT the right attitude to take, because we * might be running on an SMP box, but we'll deal with * SMP in a later chapter. */ Device_Open++; /* Initialize the message */ Message_Ptr = Message; MOD_INC_USE_COUNT; return SUCCESS; } /* This function is called when a process closes the * device file. It doesn't have a return value because * it cannot fail. Regardless of what else happens, you * should always be able to close a device (in 2.0, a 2.2 * device file could be impossible to close). */ #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0) static int device_release(struct inode *inode, struct file *file) #else static void device_release(struct inode *inode, struct file *file) #endif { #ifdef DEBUG printk ("device_release(%p,%p)\n", inode, file); #endif /* We're now ready for our next caller */ Device_Open --; MOD_DEC_USE_COUNT; #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0) return 0; #endif } /* This function is called whenever a process which * has already opened the device file attempts to * read from it. */ #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0) static ssize_t device_read( struct file *file, char *buffer, /* The buffer to fill with the data */ size_t length, /* The length of the buffer */ loff_t *offset) /* offset to the file */ #else static int device_read( struct inode *inode, struct file *file, char *buffer, /* The buffer to fill with the data */ int length) /* The length of the buffer * (mustn't write beyond that!) */ #endif { /* 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. */ #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0) static ssize_t device_write(struct file *file, const char *buffer, size_t length, loff_t *offset) #else static int device_write(struct inode *inode, struct file *file, const char *buffer, int length) #endif { int i; #ifdef DEBUG printk ("device_write(%p,%s,%d)", file, buffer, length); #endif for(i=0; i<length && i<BUF_LEN; i++) #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0) get_user(Message[i], buffer+i); #else Message[i] = get_user(buffer+i); #endif 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, struct file *file, unsigned int ioctl_num,/* The number of the ioctl */ unsigned long ioctl_param) /* The parameter to it */ { int i; char *temp; #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0) char ch; #endif /* 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 */ #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0) get_user(ch, temp); for (i=0; ch && i<BUF_LEN; i++, temp++) get_user(ch, temp); #else for (i=0; get_user(temp) && i<BUF_LEN; i++, temp++) ; #endif /* Don't reinvent the wheel - call device_write */ #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0) device_write(file, (char *) ioctl_param, i, 0); #else device_write(inode, file, (char *) ioctl_param, i); #endif break; case IOCTL_GET_MSG: /* Give the current message to the calling * process - the parameter we got is a pointer, * fill it. */ #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0) i = device_read(file, (char *) ioctl_param, 99, 0); #else i = device_read(inode, file, (char *) ioctl_param, 99); #endif /* Warning - we assume here the buffer length is * 100. If it's less than that we might overflow * the buffer, causing the process to core dump. * * The reason we only allow up to 99 characters is * that the NULL which terminates the string also * needs room. */ /* 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 = { NULL, /* seek */ device_read, device_write, NULL, /* readdir */ NULL, /* select */ device_ioctl, /* ioctl */ NULL, /* mmap */ device_open, #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0) NULL, /* flush */ #endif 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 = module_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 = module_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 <linux/ioctl.h> /* 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 <fcntl.h> /* open */ #include <unistd.h> /* exit */ #include <sys/ioctl.h> /* ioctl */ /* 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); } 9.1. ½Ã½ºÅÛ ÄÝ ¶Áö±Ý±îÁö ¿ì¸®°¡ ÇÑ °ÍÀº /procÆÄÀÏ°ú µð¹ÙÀ̽º Çîµé·¯¸¦ µî·ÏÇϱâ À§ÇØ Àß Á¤ÀÇµÈ Ä¿³Î ¸ÞÄ¿´ÏÁòÀ» »ç¿ëÇÑ °ÍÀÌ´Ù. ÀåÄ¡ µå¶óÀ̹ö¸¦ ÀÛ¼ºÇÏ´Â °Í°ú °°Àº Ä¿³Î ÇÁ·Î±×·¥À» ÇÏ´Â °Í¿¡´Â Áö±Ý±îÁöÀÇ °Íµµ ÁÁ´Ù. ±×·¯³ª ƯÁ¤ÇÑ ¹æ½ÄÀ¸·Î ½Ã½ºÅÛÀÇ ÇàÀ§¸¦ º¯°æÇÏ´Â °Í°ú °°Àº µ¶Æ¯ÇÑ °ÍÀ» ¿øÇϴ°¡? ±×·± °ÍµéÀº ÀüÀûÀ¸·Î ´ç½ÅÀÇ ¸òÀÌ´Ù.
ÀÌ ºÎºÐÀÌ Ä¿³Î ÇÁ·Î±×·¥¿¡¼ ÁÖÀÇÇØ¾ß ÇÒ ºÎºÐÀÌ´Ù. ¾Æ·¡ ¿¹Á¦¿¡¼ open() ½Ã½ºÅÛ ÄÝÀ» Á׿´´Ù. ÀÌ°ÍÀº ¾î¶² ÆÄÀϵµ ¿°Å³ª, ¾î¶² ÇÁ·Î±×·¥À» ½ÇÇàÇϰųª, ÄÄÇ»Å͸¦ ¼Ë´Ù¿î ½ÃÅ°Áöµµ ¸øÇÏ°Ô µÊÀ» ÀǹÌÇÑ´Ù. Àü¿ø ½ºÀ§Ä¡¸¦ °Á¦·Î ²¨¾ß ÇÑ´Ù. ´ÙÇàÈ÷µµ ¾î¶² ÆÄÀϵµ ¼Õ»óÀ» ÀÔÁö ¾Ê¾Ò´Ù. ¾î¶² ÆÄÀϵµ ÀÒÁö ¾Ê±â À§Çؼ´Â insmod¸¦ Çϰųª rmmod¸¦ ½ÇÇàÇϱâ Àü¿¡ sync¸¦ ½ÇÇà ½ÃÅ°ÀÚ.
/procÆÄÀÏÀ̳ª µð¹ÙÀ̽º ÆÄÀÏÀº ÀØÀÚ. ±×µéÀº °£´ÜÇÑ ¹®Á¦´Ù. ¸ðµç ÇÁ·Î¼¼½º°¡ »ç¿ëÇÏ´Â ´Ü ÇϳªÀÇ ½ÇÁ¦ ÇÁ·Î¼¼½º¿¡¼ Ä¿³Î·ÎÀÇ Åë½Å ¸ÞÄ¿´ÏÁòÀº ½Ã½ºÅÛ ÄÝÀÌ´Ù. ÆÄÀÏÀ» ¿°Å³ª »õ·Î¿î ÇÁ·Î¼¼½º¸¦ »ý¼ºÇϰųª Ãß°¡ÀûÀÎ ¸Þ¸ð¸®¸¦ ¿ä±¸ÇÏ´Â µî, ÇÁ·Î¼¼½º°¡ Ä¿³Î¿¡°Ô ¼ºñ½º¸¦ ¿ä±¸ÇÒ ¶§, ÀÌ ¸ÞÄ¿´ÏÁòÀÌ »ç¿ëµÈ´Ù. ¿øÇÏ´Â ¹æ½ÄÀ¸·Î Ä¿³ÎÀÌ ¿òÁ÷À̱⸦ ¿øÇÑ´Ù¸é ¹Ù·Î ¿©±â°¡ ÀÛ¾÷ÇØ¾ß ÇÒ ºÎºÐÀÌ´Ù. ¾î¶² ½Ã½ºÅÛ ÄÝÀÌ ÇÁ·Î±×·¥¿¡ ÀÇÇØ »ç¿ëµÇ´Â °¡¸¦ ¾Ë±â ¿øÇÑ´Ù¸é, strace <arguments> ½ÇÇà ½ÃÅ°ÀÚ.
ÀϹÝÀûÀ¸·Î ÇÁ·Î¼¼½º´Â Ä¿³Î¿¡ Á÷Á¢ÀûÀ¸·Î Á¢±ÙÇÒ ¼ö ¾ø´Ù. ÇÁ·Î¼¼½º´Â Ä¿³Î ¸Þ¸ð¸®¿¡ Á¢±ÙÇѴٰųª Ä¿³ÎÀÇ ÇÔ¼ö¸¦ È£ÃâÇÒ ¼ö ¾ø´Ù. Çϵå¿þ¾îÀÇ CPU°¡ ±×·¸°Ô Çϸç ÀÌ°ÍÀÌ º¸È£¸ðµå¶ó ºÎ¸£´Â ÀÌÀ¯´Ù.
½Ã½ºÅÛ ÄÝÀº ÀϹÝÀûÀÎ ±ÔÄ¢¿¡¼ÀÇ ¿¹¿Ü´Ù. ÇÁ·Î¼¼½º°¡ Àû´çÇÑ °ªÀ¸·Î ·¹Áö½ºÅ͸¦ ä¿ì°í, Ä¿³Î ¾È¿¡ ¹Ì¸® Á¤ÀÇ µÇÀÖ´Â À§Ä¡·Î Á¡ÇÁÇÏ´Â ÀνºÆ®·°¼Ç(¸í·É)À» È£ÃâÇÏ´Â °ÍÀÌ ¹Ù·Î ÀÌ°ÍÀÌ´Ù. ÀÎÅÚ CPU¿¡¼´Â ÀÌ°ÍÀÌ ÀÎÅÍ·´Æ® 0x80À» ÀǹÌÇÑ´Ù. ÀÏ´Ü ÀÌ À§Ä¡·Î À̵¿Çϸé Çϵå¿þ¾î´Â Á¦ÇÑ ÀûÀÎ »ç¿ëÀÚ ¸ðµå°¡ ¾Æ´Ï°í ¿î¿µÃ¼°èÀÇ Ä¿³Î·Î ÀνÄÇÑ´Ù. ºñ·Î¼Ò ¿øÇÏ´Â °ÍÀ» ÇÒ ¼ö ÀÖ´Ù.
Ä¿³Î ³»ºÎÀÇ À§Ä¡¿¡¼ ÇÁ·Î¼¼½º´Â ½Ã½ºÅÛ ÄÝ·Î Á¡ÇÁ°¡ °¡´ÉÇÏ´Ù. ÀÌ À§Ä¡¿¡¼ ÇÁ·Î½ÃÁ®´Â ½Ã½ºÅÛ ÄÝÀÇ ¹øÈ£¸¦ È®ÀÎÇÑ´Ù. ±×¸®°í ±×°ÍÀº Ä¿³Î¿¡°Ô ¾î¶² ¼ºñ½º¸¦ ÇÁ·Î¼¼½º°¡ ¿ä±¸Çß´ÂÁö ¾Ë·ÁÁØ´Ù. ±×·± ÈÄ, ½Ã½ºÅÛ ÄÝ Å×À̺í(sys_chall_tabel)À» Ä¿³Î ÇÔ¼ö¸¦ È£ÃâÇϱâ À§ÇÑ ÁÖ¼Ò¸¦ ¾Ë¾Æº¸±â À§ÇØ Á¶»çÇÑ´Ù. ±× ÈÄ ÇÔ¼ö¸¦ È£ÃâÇϸç, ÇÔ¼ö°¡ ¸®ÅÏÇÑ ÈÄ ¸î °¡Áö ½Ã½ºÅÛ Ã¼Å©¸¦ ÇÏ°í, ÇÁ·Î¼¼½º·Î µ¹¾Æ¿Â´Ù. ÀÌ Äڵ带 º¸±â¸¦ ¿øÇÑ´Ù¸é, /$<$architecture$>$/kernel/entry.SÀÇ ´ÙÀ½ ¶óÀÎÀÎ ENTRY(system_call)¿¡ ÀÖÀ¸´Ï º¸±â ¹Ù¶õ´Ù. /
ƯÁ¤ ½Ã½ºÅÛ ÄÝÀÇ ÀÛµ¿À» ¹Ù²Ù°í ½Í´Ù¸é, ÇØ¾ß ÇÒ ÀÏÀº ±× ÇÔ¼ö¸¦ ¿ì¸®ÀÇ °ÍÀ¸·Î »õ·Î ±¸ÇöÇÏ´Â °ÍÀÌ´Ù.(º¸Åë ¸î ¶óÀεǴ ¿ì¸®ÀÇ Äڵ带 ³Ö°í ¿ø·¡ÀÇ ÇÔ¼ö¸¦ È£ÃâÇÑ´Ù.) ±×¸®°ísys_call_table¿¡ ¿ì¸®°¡ ¸¸µç ÇÔ¼öÀÇ Æ÷ÀÎÅÍ·Î ´ëüÇÏ¸é µÈ´Ù. ³ªÁß¿¡ ¿ì¸®°¡ ¸¸µç °ÍÀ» Á¦°ÅÇÏ°í ½Ã½ºÅÛÀÌ ºÒ¾ÈÁ¤ÇÑ »óÅ·Π³²±â¸¦ ¹Ù¶óÁö ¾Ê´Â ´Ù¸é, cleanup_module()¿¡¼ ¿ø·¡ÀÇ »óÅ·Πsys_call_tableÀ» µ¹·Á ³õ´Â °ÍÀÌ ÇÊ¿äÇÏ´Ù.
¿©±âÀÇ ¼Ò½ºÄÚµå´Â ±×·± Ä¿³Î ¸ðµâÀÇ ¿¹´Ù. ƯÁ¤ »ç¿ëÀÚ¿¡ ´ëÇÑ ¡®½ºÆÄÀÌ¡¯¸¦ ¿øÇØ ±× »ç¿ëÀÚ°¡ ¾î¶² ÆÄÀÏÀ» ¿ ¶§¸¶´Ù prink()·Î ¸Þ½ÃÁö¸¦ Ãâ·ÂÇÑ´Ù. ÀÌ°ÍÀ» À§ÇØ open ½Ã½ºÅÛ ÄÝÀÇ Äڵ带 ¿ì¸®ÀÇ ÇÔ¼öÀÎ our_sys_open()À¸·Î ¹Ù²ã¾ß ÇÑ´Ù. ÀÌ ÇÔ¼ö´Â ÇöÀç ÇÁ·Î¼¼½ºÀÇ uid¸¦ °Ë»çÇغ» ÈÄ ¿ì¸®°¡ °¨½ÃÇÏ°íÀÚ ÇÏ´Â uid¿Í ÀÏÄ¡ ÇÒ °æ¿ì, printk()¸¦ È£ÃâÇØ ¿¸° ÆÄÀÏÀÇ À̸§À» Ãâ·ÂÇÑ´Ù. °°Àº ¹æ½ÄÀ¸·Î ½ÇÁ¦ ÆÄÀÏÀ» ¿±â À§ÇØ °°Àº ÀÎÀÚ¸¦ °¡Áö°í open()ÇÔ¼ö¸¦ È£ÃâÇÑ´Ù.
init_module() ÇÔ¼ö´Â sys_call_table¿¡¼ ¸Â´Â À§Ä¡¸¦ ´ëüÇÏ°í ¿ø·¡ ÇÔ¼öÀÇ Æ÷ÀÎÅ͸¦ º¯¼ö¿¡ º¸°üÇÑ´Ù. cleanup_module() ÇÔ¼ö´Â ±× º¯¼ö¸¦ ¿ø»ó º¹±¸ÇØ ¸ðµÎ Á¤»ó »óÅ·Πµ¹·Á ³õ´Â ´Ù. µÎ °³ÀÇ Ä¿³Î ¸ðµâÀÌ µ¿½Ã¿¡ °°Àº ½Ã½ºÅÛ ÄÝÀ» º¯°æÇÒ °¡´É¼º ´ë¹®¿¡ ÀÌ Á¢±ÙÀº À§ÇèÇÏ´Ù. A¿Í B¶ó´Â Ä¿³Î ¸ðµâÀÌ ÀÖ´Ù°í °¡Á¤ÇÏÀÚ. ±×¸®°í AÀÇ open()ÇÔ¼öÀÎ A_open ±×¸®°í BÀÇ B_openÀ̶ó ÇÏÀÚ. A ¸ðµâÀÌ Ä¿³Î¿¡ ÀûÀç µÉ ¶§, ½Ã½ºÅÛ ÄÝÀº A_openÀ¸·Î ¹Ù²î°í, ÀÏÀ» ¸¶ÃÆÀ» ¶§ ¿ø·¡ °ÍÀÎ sys_openÀ¸·Î µÇµ¹¾Æ °¥ °ÍÀÌ´Ù. ´ÙÀ½À¸·Î B ¸ðµâÀÌ ÀûÀç µÇ¸é, ½Ã½ÃÅÛ ÄÝÀ» B_openÀ¸·Î ¹Ù²Ù°í, ±×°ÍÀº ÇØÁ¦ ½Ã º¹±¸ ½ÃÄÑ¾ß ÇÒ ½Ã½ºÅÛ ÄÝÀ» A_openÀ¸·Î »ý°¢ÇÒ °ÍÀÌ´Ù.
B¸ðµâÀÌ ¸ÕÀú Á¦°Å µÉ °æ¿ì ¸ðµç °ÍÀº ±¦Âú´Ù. --- ±×°ÍÀº ´Ü¼øÈ÷ ½Ã½ºÅÛ ÄÝÀ» A_openÀ¸·Î µÇµ¹·Á ³õÀ» °ÍÀÌ´Ù. ±×·± A¸ðµâÀÌ ¸ÕÀú Á¦°ÅµÇ°í B°¡ Á¦°ÅµÇ¸é, ½Ã½ºÅÛÀº ´Ù¿îµÉ °ÍÀÌ´Ù. A ¸ðµâÀ» Á¦°ÅÇÏ´Â °ÍÀº ¿ø·¡ÀÇ ½Ã½ºÅÛ ÄÝÀ» º¹±¸ ½ÃÅ°°í B´Â ÀÌ ·çÇÁ¸¦ ºüÁ® ³ª¿Â´Ù. B¸ðµâÀÌ Á¦°Å µÉ ¶§, B´Â ¿ø·¡ÀÇ ½Ã½ºÅÛ ÄÝÀ» A_openÀ̶ó°í »ý°¢ÇÒ °ÍÀÌ´Ù. ±×·¯³ª ÀÌ°ÍÀº ´õ ÀÌ»ó ¸Þ¸ð¸®¿¡ Á¸ÀçÇÏÁö ¾Ê´Â´Ù. °£´ÜÈ÷ º¸¾Æ, ½Ã½ºÅÛ ÄÝÀÌ ¿ì¸®°¡ ÀÛ¼ºÇÑ ÇÔ¼ö¿Í °°Àº°¡, º¯È°¡ ¾ø´Â°¡¸¦ È®ÀÎÇÔÀ¸·Î½á °£´ÜÈ÷ ÇØ°áÇÒ ¼ö ÀÖÀ» °Í °°¾Æ º¸ÀδÙ.(B¸ðµâÀÌ Á¦°Å µÉ ¶§ ¾Æ¹«°Íµµ Á¦°ÅÇÏÁö ¾ÊÀ½À¸·Î½á) ±×·¯³ª ÀÌ°ÍÀº ´õ ³ª»Û ¹®Á¦¸¦ À¯¹ßÇÑ´Ù. A¸ðµâÀÌ Á¦°Å µÉ ¶§, ½Ã½ºÅÛ ÄÝÀÌ B_openÀ¸·Î ¹Ù²ï °ÍÀ¸·Î º¸°í ´õ ÀÌ»ó A_openÀ» Áö½ÃÇÏÁö ¾ÊÀ» °ÍÀÌ´Ù. ÀÌ´Â ¸Þ¸ð¸®¿¡¼ Á¦°ÅµÇ±â Àü¿¡ sys_open()À» º¹±¸ ½Ã±âÁö ¾ÊÀ» °ÍÀÌ´Ù. ºÒÇàÈ÷µµ B_openÀº ´õ ÀÌ»ó Á¸ÀçÇÏÁö ¾Ê´Â A_openÀ» È£ÃâÇÏ·Á°í ÇÏ°í B¸ðµâÀ» Á¦°ÅÇÏÁö ¾ÊÀº »óÅ¿¡¼ ½Ã½ºÅÛÀº ´Ù¿îµÉ °ÍÀÌ´Ù.
µÎ °¡Áö ¹æ¹ýÀ¸·Î À̸¦ ÇØ°áÇÒ ¼ö ÀÖ´Ù. ù ¹æ¹ýÀº ¿ø·¡ ½Ã½ºÅÛ ÄÝÀÎ sys_open()À» º¹±¸ ÇÏ´Â °ÍÀÌ´Ù. ºÒÇàÇÏ°Ôµµ sys_openÀº ´õ ÀÌ»ó Ä¿³Î ½Ã½ºÅÛ ÄÝ Å×À̺íÀÎ /proc/ksymsÀÇ ÀϺΰ¡ ¾Æ´Ï¾î ¿ì¸®°¡ Á¢±ÙÇÒ ¼ö ¾ø´Ù. ´Ù¸¥ ¹æ¹ýÀº ·¹ÆÛ·±½º Ä«¿îÅ͸¦ »ç¿ëÇØ ¸ðµâÀÌ »ç¿ëÁßÀ̶ó¸é root°¡ rmmod¸¦ ½ÇÇà ÇÒ ¼ö ¾ø°Ô ÇÏ´Â °ÍÀÌ´Ù. ÀÌ°ÍÀº »ó¿ëÁ¦Ç°¿¡¼´Â ÁÁÀº ¹æ¹ýÀ̳ª ±³À°¿ëÀ¸·Î´Â ºÎÀûÇÕÇÏ´Ù. --- ³»°¡ ¿©±â¼ ÀÌ°ÍÀ» »ç¿ëÇÏÁö ¾Ê´Â ÀÌÀ¯´Ù.
Example 8-1. procfs.c
/* syscall.c
* * System call "stealing" sample. */ /* Copyright (C) 2001 by Peter Jay Salzman */ /* The necessary header files */ /* Standard in kernel modules */ #include <linux/kernel.h> /* We're doing kernel work */ #include <linux/module.h> /* Specifically, a module */ /* Deal with CONFIG_MODVERSIONS */ #if CONFIG_MODVERSIONS==1 #define MODVERSIONS #include <linux/modversions.h> #endif #include <sys/syscall.h> /* The list of system calls */ /* For the current (process) structure, we need * this to know who the current user is. */ #include <linux/sched.h> /* In 2.2.3 /usr/include/linux/version.h includes a * macro for this, but 2.0.35 doesn't - so I add it * here if necessary. */ #ifndef KERNEL_VERSION #define KERNEL_VERSION(a,b,c) ((a)*65536+(b)*256+(c)) #endif #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0) #include <asm/uaccess.h> #endif /* 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 */ extern void *sys_call_table[]; /* UID we want to spy on - will be filled from the * command line */ int uid; #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0) MODULE_PARM(uid, "i"); #endif /* 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); /* For some reason, in 2.2.3 current->uid gave me * zero, not the real user ID. I tried to find what went * wrong, but I couldn't do it in a short time, and * I'm lazy - so I'll just use the system call to get the * uid, the way a process would. * * For some reason, after I recompiled the kernel this * problem went away. */ asmlinkage int (*getuid_call)(); /* 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 == getuid_call()) { /* getuid_call is the getuid system call, * which gives the uid of the user who * ran the process which called the system * call we got */ /* Report the file, if relevant */ printk("Opened file by %d: ", uid); do { #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0) get_user(ch, filename+i); #else ch = get_user(filename+i); #endif 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); /* Get the system call for getuid */ getuid_call = sys_call_table[__NR_getuid]; 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; } 10.1.1. printk() ´ëüÇϱ⠶´©±º°¡ Áö±Ý ´çÀå ¹«¾ó ÇØ´Þ¶ó°í ÇÏ¸é ¾î¶»°Ô Çϰڴ°¡? ´ç½ÅÀÌ »ç¶÷ÀÌ°í ´Ù¸¥ »ç¶÷ÀÌ ±ÍÂú°Ô ÇÑ´Ù¸é ´ç½ÅÀº ¡°Áö±ÝÀº ¾È µÅ, ¹Ùºü, Àú¸®°¡!¡± ¶ó°í ÇÏ¸é µÈ´Ù. ±×·¯³ª ´ç½ÅÀÌ Ä¿³Î ¸ðµâÀÌ°í ÇÁ·Î¼¼½º°¡ ±ÍÂú°Ô ÇÒ ¶§´Â ´Ù¸¥ ¹æ½ÄÀ» ÃëÇØ¾ß ÇÑ´Ù. ´ç½ÅÀÌ ÇÁ·Î¼¼½ºÀÇ ¿ä±¸¸¦ ¼öÇàÇÒ ¼ö ÀÖÀ» ¶§±îÁö ÇÁ·Î¼¼½º¸¦ Àáµé°Ô ÇØ¾ß ÇÑ´Ù. ÇÁ·Î¼¼½º´Â Ä¿³Î¿¡ ÀÇÇØ Àáµé°Å³ª ±ú¾î³¯ ¼ö ÀÖ´Ù. (ÀÌ°ÍÀÌ ÇϳªÀÇ CPU¿¡¼ ¿©·¯ °³ÀÇ ÇÁ·Î¼¼½º°¡ ½ÇÇàµÇ´Â ¹æ½ÄÀÌ´Ù.)
´ÙÀ½ÀÇ Ä¿³Î ¸ðµâÀº ÀÌ·± ¿¹´Ù. /proc/sleepÆÄÀÏÀº ¿ÀÁ÷ ÇϳªÀÇ ÇÁ·Î¼¼½º¿¡ ÀÇÇؼ¸¸ »ç¿ëµÉ ¼ö ÀÖ´Ù. ¸¸¾à ÆÄÀÏÀÌ ÀÌ¹Ì ¿·Á ÀÖ´Ù¸é, Ä¿³Î ¸ðµâÀº module_interruptible_sleep_on()ÇÔ¼ö¸¦ È£ÃâÇÑ´Ù. ÀÌ ÇÔ¼ö´Â ÀÛ¾÷ÀÇ »óÅÂ(task – ÀÛ¾÷Àº ÇÁ·Î¼¼½º¿Í È£ÃâµÇ´Â ½Ã½ºÅÛ ÄÝ¿¡ °üÇÑ Á¤º¸¸¦ °¡Áø Ä¿³ÎÀÇ µ¥ÀÌÅÍ ±¸Á¶¸¦ ¸»ÇÑ´Ù.)¸¦ TASK_INTERRUPTIBLE·Î º¯°æÇÑ´Ù. ÀÌ°ÍÀº ÀÛ¾÷ÀÌ ±ú¾î³ª ÆÄÀÏ¿¡ Á¢±ÙÇÒ ¼ö ÀÖ´Â ÀÛ¾÷ ´ë±â Å¥¿¡ ÁøÀÔµÊÀ» ÀǹÌÇÑ´Ù. ±×¸®°í ÀÌ ÇÔ¼ö´Â ½ºÄÉÁÙ·¯¸¦ È£ÃâÇØ ´Ù¸¥ ÇÁ·Î¼¼½º·Î ¹®¸ÆÀüȯ(context switch)¸¦ ÇÏ°Ô Çϸç, ±× ÇÁ·Î¼¼½º´Â CPU¸¦ »ç¿ëÇÑ´Ù.
ÇÁ·Î¼¼½º°¡ ÆÄÀÏ¿¡ ´ëÇÑ ÀÛ¾÷À» ¸¶Ä¡¸é, ÆÄÀÏÀ» ´Ý°í, module_close()ÇÔ¼ö¸¦ È£ÃâÇÑ´Ù. ÀÌ ÇÔ¼ö´Â Å¥¿¡ ÀÖ´Â ÇÁ·Î¼¼½º¸¦ ±ú¿î´Ù. (´ë±â ÁßÀÎ ÇÁ·Î¼¼½º¸¦ ±ú¿ì´Â Ưº°ÇÑ ¸ÞÄ¿´ÏÁòÀº ¾ø´Ù) ÆÄÀÏÀ» ´ÝÀº ÇÁ·Î¼¼½º´Â ´Ù¸¥ ÀÛ¾÷À» °è¼Ó ¼öÇàÇÑ´Ù. À̶§ ½ºÄÉÁÙ·¯´Â ±× ÇÁ·Î¼¼½º°¡ ÃæºÐÈ÷ ¼öÇàµÆÀ¸¸ç, ´Ù¸¥ ÇÁ·Î¼¼½º¿¡°Ô CPUÁ¡À¯±ÇÀ» ³Ñ±âµµ·Ï °áÁ¤ÇÑ´Ù. °á±¹ ÇÁ·Î¼¼½º Áß Çϳª´Â ½ºÄÉÁÙ·¯¿¡ ÀÇÇØ CPUÁ¡À¯¸¦ Çã°¡ ¹Þ°Ô µÈ´Ù. ÀÌ·± ÀÛ¾÷Àº module_interruptible_sleep_on()ÇÔ¼ö¸¦ È£ÃâÇÑ Á÷ÈÄ ¼öÇàµÈ´Ù. ÀÌ ÇÁ·Î¼¼½º´Â Àü¿ª º¯¼ö °ªÀ» ¼³Á¤ÇÏ°í, ¿©ÀüÈ÷ ÇØ´ç ÆÄÀÏÀ» »ç¿ëÇÏ·Á°í ±â´Ù¸®´Â ÇÁ·Î¼¼½º¿¡°Ô Å뺸¸¦ ÇÑ´Ù. ´Ù¸¥ ÇÁ·Î¼¼½ºµéÀÌ CPU¸¦ Á¡À¯Çϸé, ÇØ´ç Àü¿ªº¯¼öÀÇ °ªÀ» È®ÀÎÇÏ°í ´Ù½Ã ´ë±â »óÅ·Πµ¹¾Æ°£´Ù.
Èï¹Ì·Ó°Ôµµ, module_close()ÇÔ¼ö´Â ÆÄÀÏ¿¡ Á¢±ÙÇϱâ À§ÇØ ±â´Ù¸®´Â ÇÁ·Î¼¼½º¸¦ ±ú¿ì´Â °Í¿¡ ´ëÇØ µ¶Á¡±ÇÀ» °¡ÁöÁö ¸øÇÑ´Ù. Ctrl+c (SIGINT)°°Àº ½Ã±×³Îµµ ÇÁ·Î¼¼½º¸¦ ±ú¿ï ¼ö ÀÖ´Ù.3 ÀÌ·± °æ¿ì ¿ì¸®´Â –EINTR·Î ¼³Á¤µÈ °ªÀ» Áï°¢ µ¹·Á ¹Þ´Â´Ù. ÀÏ·Ê·Î ÇÁ·Î¼¼½º°¡ ÆÄÀÏÀ» ¿±â Àü¿¡ »ç¿ëÀÚ°¡ ±×°ÍÀ» Á×ÀÏ ¼ö ÀÖ´Ù´Â Á¡¿¡¼ Áß¿äÇÏ´Ù.
±â¾ïÇØ ¾ßÇÒ »çÇ×ÀÌ Çϳª ´õ ÀÖ´Ù. °¡²û ´ë±â »óÅ·Π¹Ù²î´Â °ÍÀ» ¿øÄ¡ ¾Ê´Â ÇÁ·Î¼¼½º°¡ ÀÖ´Ù. ±×µéÀº ±×µéÀÌ ¿øÇÏ´Â °ÍÀ» Áï°¢ÀûÀ¸·Î °®±â¸¦ ¿øÇϰųª ÀÛ¾÷À» ÁøÇàÇÒ ¼ö ¾ø´Ù°í º¸°í ÇÏ±æ ¿øÇÑ´Ù. ±×·± ÇÁ·Î¼¼½ºµéÀº ÆÄÀÏÀ» ¿ ¶§O_NONBLOCK Ç÷¡±×¸¦ ¼³Á¤ÇÑ´Ù. ´ÙÀ½ÀÇ ¿¹¿Í °°ÀÌ ÆÄÀÏÀ» ¿ ¶§ ºí·Ï ´çÇϱ⠺¸´Ù -EAGAIN À̶ó´Â ¿¡·¯Äڵ带 ¸®ÅÏÇÔÀ¸·Î½á Ä¿³ÎÀÌ ÀÀ´äÇÑ´Ù. ÀÌ Àå¿¡¼ ¿¹·Î º¼ ¼ö ÀÖ´Â cat_noblock ÇÁ·Î±×·¥Àº O_NONBLOCK Ç÷¡±×¸¦ ¼³Á¤ÇÑ Ã¼, ÆÄÀÏÀ» ¿°Ô µÉ °ÍÀÌ´Ù.
Example 9-1. sleep.c
11.1. printK()´ëüÇϱ⠶¼½¼Ç Section 1.2.1.2¿¡¼ X¿Í Ä¿³Î ¸ðµâ ÇÁ·Î±×·¡¹ÖÀ» ÇÔ²² »ç¿ëÇÏÁö ¸»¶ó°í Çß´Ù. Ä¿³Î ¸ðµâÀ» °³¹ßÇÏ´Â °úÁ¤¿¡¼´Â ¸Â´Â ¸»ÀÌ´Ù. ±×·¯³ª ½ÇÁ¦ÀÇ °æ¿ì¿¡¼´Â ¸ðµâÀ» ÀûÀçÇϱâ À§ÇÑ tty¸í·ÉÀ» º¸³¾ ¼ö Àֱ⸦ ¿øÇÒ °ÍÀÌ´Ù.
ÇöÀç ½ÇÇà ÁßÀÎ ÇöÀç ŽºÅ©ÀÇ tty ±¸Á¶Ã¼¸¦ ±¸Çϱâ À§ÇØ, ŽºÅ©¸¦ Áö½ÃÇÏ´Â current ¸ÅÅ©·Î¸¦ »ç¿ëÇؼ ÇØ°áÇÒ ¼ö ÀÖ´Ù. ¹®ÀÚ¿À» ¾µ ¼ö ÀÖ´Â ÇÔ¼öÀÇ Æ÷ÀÎÅ͸¦ ã±â À§ÇØ tty±¸Á¶Ã¼¸¦ µé¿©´Ùº»´Ù, ±×°ÍÀ» ÀÌ¿ëÇØ tty¿¡ ¹®ÀÚ¿À» Ãâ·Â ÇÑ´Ù.
Example 10-1. print_string.c
12.1. ÀÛ¾÷ ½ºÄÉÁÙ¸µÇϱ⠶¿ì¸®´Â Á¾Á¾ ¡°°¡Á¤ºÎ¡± ÀÏÀ» ÇÑ´Ù. ±×¸®°í ±× ÀÏÀº ÀÚÁÖÀÌ´ø °¡²ûÀÌ´ø ƯÁ¤ ½Ã°¢¿¡ ÇàÇØÁ®¾ß ÇÑ´Ù. ±× ÀÏÀ» ÇÁ·Î¼¼½º°¡ ÇÑ´Ù¸é, crontabÆÄÀÏ¿¡ ÀÔ·ÂÇÏ´Â °ÍÀ¸·Î ÇØ°áÇÒ ¼ö ÀÖ´Ù. ¸¸ÀÏ ÀÌ·± ÀÏÀ» Ä¿³Î ¸ðµâÀÌ ÇØ¾ß ÇÑ´Ù¸é, µÎ °¡Áö ¹æ¹ýÀÌ ÀÖ´Ù. ù°·Î ÇÊ¿äÇÒ ¶§, ½Ã½ºÅÛ ÄÝ¿¡ ÀÇÇØ ¸ðµâÀ» ±ú¿ì´Â ÇÁ·Î¼¼½º¸¦ crontab ÆÄÀÏ¿¡ Áý¾î ³Ö´Â °ÍÀÌ´Ù. ±×·¯³ª ÀÌ°ÍÀº ²ûÂïÇÏ°Ôµµ ºñÈ¿À²ÀûÀÌ´Ù. ÀÌ°ÍÀº »õ ÇÁ·Î¼¼½º¸¦ crontab¿¡¼ ½ÇÇà ½ÃÅ°°í, ½ÇÇà °¡´É Äڵ带 ¸Þ¸ð¸®¿¡¼ Àд´Ù. ´ÜÁö ¸Þ¸ð¸®¿¡ ÀÌ¹Ì Á¸ÀçÇÏ´Â Ä¿³Î ¸ðµâÀ» ±ú¿ì±â À§Çؼ ¸»ÀÌ´Ù.
ÀÌ·¸°Ô ÇÏ´Â °Í ¸»°í, ŸÀÌ¸Ó ÀÎÅÍ·´Æ® ¶§¸¶´Ù È£ÃâµÇ´Â ÇÔ¼ö¸¦ ¸¸µé ¼ö ÀÖ´Ù. ÀÌ·± ÀÏÀ» ÇÏ´Â ¹æ¹ýÀº »õ·Î¿î ÀÛ¾÷(task)¸¦ ¸¸µé°í, ÇÔ¼öÀÇ Æ÷ÀÎÅ͸¦ °¡Áö°í ÀÖ´Â tq_struct ±¸Á¶Ã¼¿¡ º¸°üÇÏ´Â °ÍÀÌ´Ù. ±×¸®°í³ª¼ queue_task() ÇÔ¼ö¸¦ tq_timer(ÀÌ°ÍÀº ´ÙÀ½ ŸÀÓ ÀÎÅÍ·´Æ® ¶§ ½ÇÇàµÉ ÀÛ¾÷ÀÇ ¸®½ºÆ®¸¦ °¡Áö°í ÀÖ´Ù.)¶ó°í ºÒ¸®´Â ÀÛ¾÷ ¸®½ºÆ®¿¡ Áý¾î ³Ö±â À§ÇØ »ç¿ëÇÑ´Ù. ÀÌ ÇÔ¼ö°¡ ½ÇÇà ÁßÀÎ °ÍÀ¸·Î À¯ÁöµÇ±â ¹Ù¶ó±â ¶§¹®¿¡, ÀÌ°ÍÀÌ È£ÃâµÉ ¶§¸¶´Ù ´ÙÀ½ ½Ã°£ ÀÎÅÍ·´Æ®¸¦ ´ëºñÇØ, ´Ù½Ã tq_timer¿¡ Áý¾î³Ö´Â´Ù.
±â¾ïÇÒ »çÇ×ÀÌ Çϳª ´õ ÀÖ´Ù. ¸ðµâÀÌ rmmod¿¡ ÀÇÇØ Á¦°Å µÉ ¶§, ·¹ÆÛ·±½º Ä«¿îÆ®°¡ Á¡°ËµÈ´Ù. ±× °ªÀÌ 0ÀÏ ¶§, module_cleanup()ÀÌ È£ÃâµÈ´Ù. ±×Á¦¼¾ß ¸ðµâÀÌ ÀÌ ÇÔ¼ö¿¡ ÀÇÇØ ¸Þ¸ð¸®¿¡¼ Á¦°ÅµÈ´Ù. ¾î´À ´©±¸µµ timer¡¯s task list¿¡ ÀÌ·± ´õ ÀÌ»ó »ç¿ëÇÏÁö ¾Ê´Â ÇÔ¼öÀÇ Æ÷ÀÎÅÍ°¡ ÀÖ´ÂÁö È®ÀÎÇÏÁö ¾Ê´Â´Ù. ÇÑÂü Àü¿¡( ÀÌ°ÍÀº ¾îµð±îÁö³ª ÄÄÇ»ÅÍÀÇ °üÁ¡ÀÌ´Ù. Àΰ£ÀÇ °üÁ¡¿¡¼ º¸¸é ¸¹¾Æ¾ß ¼ö ¹é ÃÊ ÀüÀÌ´Ù.) Ä¿³ÎÀº ŸÀÌ¸Ó ÀÎÅÍ·´Æ®¸¦ ¹Þ¾Ò°í, ÀÛ¾÷¸®½ºÆ®¿¡ ÀÖ´Â ÇÔ¼ö¸¦ È£ÃâÇß´Ù. ºÒÇàÈ÷µµ ±× ÇÔ¼ö´Â ´õ ÀÌ»ó ±×°÷¿¡ Á¸ÀçÇÏÁö ¾Ê´Â´Ù. ´ëºÎºÐÀÇ °æ¿ì, ÇÔ¼ö°¡ Á¸ÀçÇÏ´ø ¸Þ¸ð¸®ÀÇ ÆäÀÌÁö´Â ´õ ÀÌ»ó »ç¿ëµÇÁö ¾ÊÀ¸¸ç, ´ç½ÅÀº ÁöÀúºÐÇÑ ¿¡·¯ ¸Þ½ÃÁö¸¦ ¹ÞÀ» °ÍÀÌ´Ù. ±×·¯³ª °°Àº ¸Þ¸ð¸®ÀÇ À§Ä¡¿¡ »õ·Î¿î Äڵ尡 ÀÚ¸®Àâ¾Ò´Ù¸é, »çÅ´ ´õ ³ªºüÁø´Ù. ºÒÇàÈ÷µµ ¿ì¸®´Â ÀÛ¾÷¸®½ºÆ®(task list)¿¡¼ ÀÛ¾÷À» Á¦°ÅÇÏ´Â ½¬¿î ¹æ¹ýÀÌ ¾ø´Ù.
cleanup_module()ÇÔ¼ö´Â ¿¡·¯Äڵ带 ¸®ÅÏÇÒ ¼ö ¾ø±â ¶§¹®¿¡(ÀÌ°ÍÀº void¸¦ ¸®ÅÏÇÑ´Ù.), ÇØ°áÃ¥Àº ¾Æ¹«°Íµµ ¸®ÅÏÇÏ°Ô ÇÏÁö ¸øÇÏ´Â °ÍÀÌ´Ù. ´ë½Å sleep_on() ȤÀº module_sleep_on()À» È£ÃâÇØ rmmodÇÁ·Î¼¼½º¸¦ Àáµé°Ô ÇÑ´Ù. ±×·¯±â Àü¿¡, ŸÀÌ¸Ó ÀÎÅÍ·´Æ®¿¡¼ È£ÃâµÈ ÇÔ¼ö¿¡°Ô Àü¿ªº¯¼ö¸¦ ¼³Á¤ÇÔÀ¸·Î½á ÀÚ½ÅÀ» ´õ ÀÌ»ó Ãß°¡ÇÏÁö ¸»µµ·Ï ¾Ë¸°´Ù. ´ÙÀ½ ¹ø ŸÀÓ ÀÎÅÍ·´Æ® ¶§¿¡ rmmodÇÁ·Î¼¼½º°¡ ±ú¾î³ª°í, ±×¶§´Â ¿ì¸®ÀÇ ÇÔ¼ö°¡ ´õ ÀÌ»ó Å¥¿¡ ÀÖÁöµµ ¾Ê°í, ¸ðµâÀ» Á¦°ÅÇϴµ¥µµ ¾ÈÀüÇÏ°Ô µÈ´Ù.
Example 11-1. sched.c
13.1.1. ÀÎÅÍ·´Æ® Çڵ鷯 ¶ÃֽŠÄÄÇ»Å͸¦ Á¦¿ÜÇÏ°í, ÇÁ·Î¼¼½º°¡ ¿äûÇÑ °Í¿¡ ´ëÇØ, Ư¼ö ÆÄÀÏÀ» ´Ù·ç°Å³ª ioctl()À» »ç¿ëÇϰųª, ½Ã½ºÅÛ ÄÝÀ» »ç¿ëÇÔÀ¸·Î½á ¿ì¸®°¡ Áö±Ý±îÁö Ä¿³Î¿¡ ÇÑ ¸ðµç ÀÛ¾÷À» Çß´Ù. ±×·¯³ª Ä¿³ÎÀÇ ¿ªÇÒÀº ÇÁ·Î¼¼½ºÀÇ ¿äû¿¡ ÀÀ´äÇÏ´Â °Í¸¸Àº ¾Æ´Ï´Ù. ¸ðµç ¼ø°£ Áß¿äÇÑ ¶Ç ´Ù¸¥ Ä¿³ÎÀÇ ÀÛ¾÷Àº Àåºñ¿¡ ¿¬°áµÈ Çϵå¿þ¾î¿Í ÀÇ»ç ¼ÒÅëÇÏ´Â °ÍÀÌ´Ù.
CPU¿Í ³ª¸ÓÁö Çϵå¿þ¾î°£¿¡ ÀÇ»ç ¼ÒÅëÀ» ÇÏ´Â ¹æ½ÄÀº µÎ °¡Áö°¡ ÀÖ´Ù. ù ¹æ½ÄÀº CPU°¡ Çϵå¿þ¾î¿¡ ¸í·ÉÀ» ³»¸®°í, CPU¿¡°Ô Çϵå¿þ¾î°¡ ¹«¾ð°¡ ÇÊ¿äÇÏ´Ù°í ¸»ÇÏ´Â ¹æ½ÄÀÌ´Ù. ÀÎÅÍ·´Æ®¶ó ºÒ¸®´Â µÎ ¹ø° ¹æ½ÄÀº CPU°¡ ¾Æ´Ñ Çϵå¿þ¾îÀÇ ÆíÀǸ¦ ´Ù·ç´Â °ÍÀ̱⠶§¹®¿¡ ±¸ÇöÀÌ ´õ ¾î·Æ´Ù. Çϵå¿þ¾î ÀåÄ¡´Â º¸ÆíÀûÀ¸·Î ¸Å¿ì ÀÛÀº ¾çÀÇ RAMÀ» °¡Áö°í ÀÖ°í, ¸¸¾à °¡´ÉÇÒ ¶§ ´ç½ÅÀÌ ±× Á¤º¸¸¦ ÀÐÁö ¾Ê´Â ´Ù¸é ±×°ÍÀº »ç¶óÁø´Ù.
À¯´Ð½º¿¡¼´Â Çϵå¿þ¾î ÀÎÅÍ·´Æ®¸¦ IRQ¶ó ºÎ¸¥´Ù. short¿Í long ŸÀÔÀÇ µÎ °¡Áö IRQ°¡ Á¸ÀçÇÑ´Ù. short IRQ´Â ¸Å¿ì ªÀº ½Ã°£ÀÌ °É¸®´Â °ÍÀÌ°í, ±× ½Ã°£ µ¿¾È ´Ù¸¥ ÀÎÅÍ·´Æ®°¡ 󸮵ÇÁö ¾Ê°í ÀåºñÀÇ ³ª¸ÓÁö Àåºñ°¡ ¸ðµÎ ºí·ÏµÈ´Ù. long IRQ´Â ºñ±³Àû ±ä ½Ã°£ÀÌ °É¸®°í, ±× ½Ã°£ µ¿¾È ´Ù¸¥ ÀÎÅÍ·´Æ®°¡ ¹ß»ýÇÒ ¼öµµ ÀÖ´Ù. (±×·¸Áö¸¸ °°Àº ÀåÄ¡·ÎºÎÅÍ ¹ß»ýÇÒ ¼ö´Â ¾ø´Ù.) ÀÌ ¸ðµç °¡´É¼ºÀ» °í·ÁÇÑ´Ù¸é, ÀÎÅÍ·´Æ® Çڵ鷯¸¦ long ŸÀÔÀ¸·Î ¼¾ð ÇÏ´Â °ÍÀÌ ³´´Ù.
CPU°¡ ÀÎÅÍ·´Æ®¸¦ ¹ÞÀ¸¸é, ±×°ÍÀº ÇÏ´ø ¸ðµç ÀÏÀ» ¸ØÃß°í(´õ Áß¿äÇÑ ÀÎÅÍ·´Æ® 󸮸¦ ÇÏ°í ÀÖÁö ¾Ê´Ù¸é, ÀÌ °æ¿ì, Á»´õ Áß¿äÇÑ ÀÎÅÍ·´Æ® 󸮰¡ ó¸®µÈ ÈÄ ±×°ÍÀ» ó¸®ÇÑ´Ù.), ½ºÅÿ¡ ƯÁ¤ ÆĶó¹ÌÅ͸¦ ÀúÀåÇÑ ÈÄ ÀÎÅÍ·´Æ® Çڵ鷯¸¦ È£ÃâÇÑ´Ù. ÀÌ°ÍÀº ½Ã½ºÅÛÀÌ ¾î¶² »óÅ¿¡ ÀÖ´ÂÁö ¾ËÁö ¸øÇϱ⠶§¹®¿¡, ¾î¶² °ÍµéÀº ÀÎÅÍ·´Æ® Çڵ鷯 ³»ºÎ¿¡¼´Â Çã°¡ µÇÁö ¾ÊÀ½À» ÀǹÌÇÑ´Ù. ÀÌ ¹®Á¦ÀÇ ÇØ°áÃ¥Àº Áï°¢ 󸮵Ǿî¾ß ÇÏ´Â ÀÎÅÍ·´Æ® Çڵ鷯°¡ ÀϹÝÀûÀ¸·Î Çϵå¿þ¾î¿¡¼ ¹«¾ùÀΰ¡¸¦ Àаųª Çϵå¿þ¾î¿¡ ¾î¶² °ÍÀ» Àü´ÞÇÏ°í ³ª¼ »õ·Î¿î Á¤º¸¸¦ ó¸®ÇÏ´Â ½ºÄÉÁÙ·¯¸¦ ½ÇÇà ½ÃÅ°´Â °ÍÀÌ´Ù.(¿ì¸®´Â ÀÌ°ÍÀ» bottom half¶ó ºÎ¸¥´Ù. Ä¿³ÎÀº °¡´ÉÇÑ »¡¸® bottom half¸¦ È£ÃâÇÒ °ÍÀÌ¶ó ¿©°ÜÁø´Ù. -- ±×¸®°í ±×·¸°Ô µÆÀ» ¶§, Ä¿³Î ¸ðµâ¿¡¼ Çã°¡µÈ ¸ðµç °ÍÀÌ ¼öÇà µÉ ¼ö ÀÖ´Ù.
ÀÌ ¹æ½ÄÀº »ó´ëÀûÀÎ IRQ¸¦ ¹Þ¾ÒÀ» ¶§, ÀÎÅÍ·´Æ® Çڵ鷯¸¦ ã±â À§ÇØ request_irq()ÇÔ¼ö¸¦ È£ÃâÇÔÀ¸·Î½á ±¸ÇöµÈ´Ù. ÀÌ ÇÔ¼ö´Â IRQ¹øÈ£, ÇÔ¼öÀÇ À̸§, Ç÷¡±× °ª, /proc/interupts¿¡ ´ëÇÑ À̸§, ÀÎÅÍ·´Æ® Çڵ鷯¿¡ Àü´ÞµÉ ÀÎÀÚ¸¦ Àü´Þ ¹Þ´Â´Ù. ÀÌ ¶§, Ç÷¡±×´Â ´Ù¸¥ ÀÎÅÍ·´Æ® Çڵ鷯¿Í IRQ¸¦ °øÀ¯ÇÏ°Ú´Ù´Â °ÍÀ» ¾Ë¸®´Â SA_SHIRQ(º¸Åë, Çϵå¿þ¾î µð¹ÙÀ̽ºÀÇ ¹øÈ£°¡ °°Àº IRQ¿¡ ÀÇÇØ ¹ß»ýÇϱ⠶§¹®¿¡), ºü¸¥ ó¸®µÅ¾ß ÇÔÀ» ¾Ë¸®´Â SA_INTERRUPT¸¦ Æ÷ÇÔÇÑ´Ù. ¼·Î °øÀ¯ÇÏ·Á°í Çϰųª, IRQ¿¡ ´Ù¸¥ Çڵ鷯°¡ Á¸ÀçÇÏÁö ¾ÊÀ» ¶§¸¸ ÀÌ ÇÔ¼ö´Â ¼º°øÇÑ´Ù.
ÀÎÅÍ·´Æ® Çڵ鷯 ³»ºÎ·ÎºÎÅÍ, ¿ì¸®´Â Çϵå¿þ¾î¿Í Åë½ÅÇÒ ¼ö ÀÖ°í, bottom half¸¦ ½ºÄÉÁÙ Çϱâ À§ÇØ, queue_task_irq()ÇÔ¼ö¿Í mark_bh(BH_IMMEDIATE)¸¦ »ç¿ëÇÑ´Ù. ¿ì¸®°¡ Ç¥ÁØÀÇ queue_task()ÇÔ¼ö¸¦ ¹öÀü 2.0¿¡¼ »ç¿ëÇÏÁö ¸øÇÏ´Â °ÍÀº ÀÎÅÍ·´Æ®°¡ ´Ù¸¥ »ç¶÷ÀÇ queue_task()ÇÔ¼ö ½ÇÇà Áß¿¡ ¹ß»ýÇÒ ¼ö Àֱ⠶§¹®ÀÌ´Ù. Ãʱ⠹öÀüÀÇ ¸®´ª½º¸¸ÀÌ 32°³ ¹è¿ÀÇ bottom half¸¦ °¡Á³°í, ±× Áß Çϳª(BH_IMMEDIATE)´Â bottom halfÀÇ ¿£Æ®¸®¸¦ ÇÒ´çÇÏÁö ¾ÊÀº µå¶óÀ̹öÀÇ bottom halfÀÇ ¸µÅ©µå ¸®½ºÆ®¸¦ À§ÇØ »ç¿ëÇÑ´Ù.
13.1.2. ÀÎÅÚ ¾ÆÅ°ÅØÃÄ¿¡¼ÀÇ Å°º¸µå ¶ÀÌ ÀåÀÇ ³ª¸ÓÁö ºÎºÐÀÇ ÀüÀûÀ¸·Î ÀÎÅÚ °è¿¿¡¸¸ Àû¿ëµÈ´Ù. ´Ù¸¥ Ç÷¿Æû¿¡¼ ÀÛµ¿½ÃÄ×´Ù¸é, ÀÛµ¿ÇÏÁö ¾ÊÀ» °ÍÀÌ´Ù. ¸¸ÀÏ ±×·¸´Ù¸é ÄÄÆÄÀÏ ½Ãµµµµ ÇÏÁö ¸»ÀÚ.
ÀÌ ÀåÀÇ ¿¹Á¦ Äڵ带 ÀÛ¼ºÇϴµ¥ ¹®Á¦°¡ ÀÖ¾ú´Ù. ÇÑÆíÀ¸·Î´Â ¸ðµç »ç¶÷ÀÇ ÄÄÇ»ÅÍ¿¡¼ ÀÛµ¿ ÇÏ¸é¼ À¯¿ëÇÑ ¿¹Á¦, ´Ù¸¥ ÇÑÆíÀ¸·Î´Â Ä¿³ÎÀÌ ÀÌ¹Ì Æ÷ÇÔÇÏ°í ÀÖ´Â ÀϹÝÀûÀÎ µð¹ÙÀ̽º µå¶óÀ̹ö, ±×¸®°í ³»°¡ Áö±Ý ÀÛ¼ºÇÏ·Á°í ÇÏ´Â °Í°ú ÀÏÄ¡ÇÏÁö ¾Ê´Â °Í. ã¾Æ³½ ÇØ°áÃ¥Àº Å°º¸µå ÀÎÅÍ·´Æ®¿¡ ´ëÇØ ¹«¾ùÀΰ¡ ÀÛ¼ºÇÏ´Â °ÍÀÌ°í, ¿ì¼±Àº ÀϹÝÀûÀÎ Å°º¸µå ÀÎÅÍ·´Æ®¸¦ ÁßÁö ½ÃÅ°´Â °ÍÀÌ´Ù. static symbol·Î ÀÌ¹Ì Ä¿³Î ³»ºÎ¿¡ Á¤ÀÇ µÅÀֱ⠶§¹®¿¡(ƯÈ÷ drivers/char/keyboard.c), ±×°ÍÀ» º¹±¸ÇÒ ¹æ¹ýÀº ¾ø´Ù. ÀÌ Äڵ带 ÀûÀçÇϱâ Àü¿¡ 120 µ¿¾È ´Ù¸¥ Å͹̳ÎÀ» ÀáÀç¿ìÀÚ.(sleep 120); ¸¸ÀÏ ´ç½ÅÀÇ ÆÄÀÏ ½Ã½ºÅÛÀ» Áß¿äÇÏ°Ô ¿©±ä´Ù¸é rebootÇÏÀÚ.
ÀÌ ÄÚµå´Â ÀÚ½ÅÀ» IRQ1¿¡ ¹ÙÀÎµå ½ÃÅ°¸ç, IRQ1Àº ÀÎÅÚ ¾ÆÅ°ÅØÃÄ ¾Æ·¡¼ Å°º¸µå IRQÀÌ´Ù. ÀÌ Äڵ尡 Å°º¸µå ÀÎÅÍ·´Æ®¸¦ ¹ÞÀ» ¶§, Å°º¸µåÀÇ »óŸ¦ Àоî¿À°í(inb(0x64)¸¦ Çϱâ À§ÇÑ °ÍÀÌ´Ù.), Äڵ带 ½ºÄµÇÑ´Ù. ±×¸®°í ±× ÄÚµå´Â Å°º¸µå¿¡ ÀÇÇØ ¸®ÅϵǴ °ªÀÌ´Ù. Ä¿³ÎÀÌ ÀÌ°ÍÀ» ½ÇÇà °¡´ÉÇÑ °ÍÀ̶ó°í ÆÇ´ÜÇÏÀÚ¸¶ÀÚ, got_char()ÇÔ¼ö¸¦ ½ÇÇà ½ÃÅ°¸ç, ÀÌ ÇÔ¼ö´Â »ç¿ëµÈ Å°ÀÇ Äڵ带 ÁÖ°í(½ºÄµÇÑ ÄÚµåÀÇ Ã¹ 7ºñÆ®), ±×°ÍÀÌ ´·È´ÂÁö(ÀÌ °æ¿ì 8¹ø° ºñÆ®°¡ 0ÀÌ´Ù), ´·È´Ù ¶³¾îÁ³´ÂÁö(ÀÌ °æ¿ì´Â 1) ¾Ë·ÁÁØ´Ù.
Example 12-1. intrpt.c
14.1. ´ëĪÀû ´ÙÁß Ã³¸®(ÇÁ·Î¼¼½Ì) ¶Çϵå¿þ¾î ¼º´É Çâ»óÀ» À§ÇÑ °¡Àå ½±°í Àú·ÅÇÑ ¹æ¹ý Áß Çϳª°¡ º¸µå¿¡ CPU¸¦ Çϳª ´õ ¼³Ä¡ÇÏ´Â °ÍÀÌ´Ù. ¼·Î ´Ù¸¥ CPU°¡ ¼·Î ´Ù¸¥ ÀÛ¾÷À» ¼öÇàÇÏ°Ô ÇÏ´Â °Í(ºñ´ëĪÀû ´ÙÁß Ã³¸®)À¸·Î ½ÇÇöµÉ ¼ö ÀÖÀ¸¸ç, °°Àº ÀÏÀ» º´ÇàÀûÀ¸·Î ½ÇÇàÇÏ°Ô ÇÔ(´ëĪÀû ´ÙÁß Ã³¸®)À¸·Î½áµµ °¡´ÉÇÏ´Ù. È¿°úÀûÀÎ ºñ´ëĪ ´ÙÁß Ã³¸®¸¦ À§Çؼ´Â ÄÄÇ»ÅÍ°¡ ÇÏ´Â ÀÛ¾÷¿¡ ´ëÇÑ Æ¯º°ÇÑ Áö½ÄÀÌ ÇÊ¿äÇϸç, ¸®´ª½º °°Àº ÀϹÝÀûÀÎ ¸ñÀûÀÇ ¿î¿µÃ¼°è¿¡¼´Â »ç¿ëÇÒ ¼ö ¾ø´Â °ÍÀÌ´Ù. ¹Ý¸é¿¡, ´ëĪÀû ´ÙÁß Ã³¸®´Â »ó´ëÀûÀ¸·Î ±¸ÇöÇϱ⠽±´Ù.
»ó´ëÀûÀ¸·Î ½±°Ô, ½ÇÁ¦ ½±Áö ¾Ê¾ÒÀ½À» ¸»ÇÒ ¼ö ÀÖ´Ù. ´ëĪ ´ÙÁß ÇÁ·Î¼¼½º ȯ°æ¿¡¼, CPU´Â °°Àº ¸Þ¸ð¸®¸¦ °øÀ¯ÇÏ°í °á°úÀûÀ¸·Î, ÇϳªÀÇ CPU¿¡¼ ½ÇÇàµÇ´Â ÄÚµå´Â ´Ù¸¥ CPU°¡ »ç¿ëÇÏ´Â ¸Þ¸ð¸®¸¦ º¯°æ½Ãų ¼ö ÀÖ´Ù. ÀÌÀü¿¡ °ªÀ» ³ÖÀº º¯¼ö°¡ ¿©ÀüÈ÷ °°Àº °ªÀ» °¡Áö°í ÀÖ´Ù°í È®½ÅÇÒ ¼ö ¾ø´Ù. ´ç½ÅÀÌ ÁÖÀǸ¦ ±â¿ïÀÌÁö ¾Ê´Â »çÀÌ¿¡ ´Ù¸¥ CPU°¡ ±× º¯¼ö¸¦ ¾î¶»°Ô ÇßÀ» ¼öµµ ÀÖ´Ù. ¸í¹éÇÏ°Ôµµ, ÇÁ·Î±×·¥À» ÀÌ·± ½ÄÀ¸·Î ÇÒ ¼ö´Â ¾ø´Ù.
ÇÁ·Î¼¼½º ÇÁ·Î±×·¡¹ÖÀÇ °æ¿ì¿¡¼, ÇÁ·Î¼¼½º´Â ÀϹÝÀûÀ¸·Î ÇϳªÀÇ CPU¿¡¼ ½ÇÇàµÇ±â ¶§¹®¿¡ ÀϹÝÀûÀ¸·Î ÀÌ·± °ÍÀº ¹®Á¦°¡ µÇÁö ¾Ê´Â´Ù. ¹Ý¸é¿¡ Ä¿³ÎÀº ¼·Î ´Ù¸¥ CPU¿¡¼ ½ÇÇàµÇ´Â ÇÁ·Î¼¼½º¿¡ ÀÇÇØ È£Ãâ µÉ ¼ö ÀÖ´Ù.
Àüü Ä¿³ÎÀÌ ÇϳªÀÇ °Å´ëÇÑ spinlock() À̱⠶§¹®¿¡, 2.0.x¹öÀü¿¡¼´Â ÀÌ°ÍÀÌ ¹®Á¦°¡ µÇÁö ¾Ê¾Ò´Ù. ¿¹¸¦ µé¾î, ÇϳªÀÇ CPU°¡ Ä¿³ÎÀ» »ç¿ëÇÒ ¶§, ½Ã½ºÅÛ ÄÝ¿¡ ÀÇÇØ ´Ù¸¥ CPU°¡ Ä¿³ÎÀ» ¿äûÇϸé, ±×°ÍÀº óÀ½ CPU°¡ ÀÏÀ» ¸¶Ä¥ ¶§±îÁö, ±â´Ù·Á¾ß ÇÑ´Ù. ÀÌ°ÍÀº SMP¸¦ ¾ÈÀüÇÏ°Ô ¸¸µé¾úÁö¸¸ È¿À²À» ¶³¾î¶ß·È´Ù.
¹öÀü 2.2.x¿¡¼´Â ¿©·¯ °³ÀÇ CPU°¡ µ¿½Ã¿¡ Ä¿³ÎÀ» »ç¿ëÇÒ ¼ö ÀÖ´Ù. ÀÌ°ÍÀÌ ¸ðµâÀ» ÀÛ¼ºÇÏ´Â »ç¶÷ÀÌ ÁÖÀÇ ÇØ¾ß ÇÒ °ÍÀÌ´Ù.
15.1. ÈçÇÑ ÇÔÁ¤ ¶´ç½ÅÀÌ ¼¼»óÀ¸·Î ³ª°¡ Ä¿³Î ¸ðµâÀ» ÀÛ¼ºÇϱâ Àü¿¡, ´ç½Å¿¡°Ô ÁÖÀǸ¦ ÁÖ¾î¾ß ÇÒ °ÍµéÀÌ ¸î °¡Áö ÀÖ´Ù. ³»°¡ Ãæ°í¸¦ ÁÖÁö ¸øÇØ ³ª»Û ÀÏÀÌ ¹ß»ýÇÑ´Ù¸é, ±× ¹®Á¦¸¦ ³ª¿¡°Ô ¾Ë·ÁÁÖ±æ ¹Ù¶õ´Ù.
Ç¥ÁØ ¶óÀ̺귯¸®¸¦ »ç¿ëÇÏ´Â °Í
Ç¥ÁØ ¶óÀ̺귯¸®´Â »ç¿ëÇÒ ¼ö ¾ø´Ù. ´ç½ÅÀÌ Ä¿³Î ¸ðµâ¿¡¼ »ç¿ë ÇÒ ¼ö ÀÖ´Â ÇÔ¼ö´Â /proc/ksyms¿¡¼ º¸ÀÌ´Â ÇÔ¼öµé »ÓÀÌ´Ù.
ÀÎÅÍ·´Æ®¸¦ ºÒ°¡´ÉÇÏ°Ô ÇÏ´Â °Í
ÀÌ°ÍÀº Àá½Ã µ¿¾È ½á¾ß ÇÒ ÇÊ¿äµµ ÀÖ°í, ±×·± °ÍÀº ±¦Âú´Ù. ±×·¯³ª ´Ù½Ã ÀÎÅÍ·´Æ®¸¦ °¡´ÉÇÏ°Ô ÇسõÁö ¾Ê´Â ´Ù¸é, ´ç½ÅÀÇ ½Ã½ºÅÛ¿¡ ¹®Á¦°¡ ¹ß»ýÇÒ °ÍÀÌ°í, Àü¿øÀ» ³»·Á¾ß¸¸ ÇÒ °ÍÀÌ´Ù.
¸Ó¸®¸¦ ´ëÇü À°½Äµ¿¹°ÀÇ ÀÔ ¾È¿¡ Âñ·¯ ³Ö´Â ÀÏ
ÀÌ·± °Í±îÁö Ãæ°íÇØ¾ß ÇÒ ÇÊ¿ä´Â ¾øÀ» °Í °°Áö¸¸, Ȥ½Ã³ª Çؼ ¾î·µç ¾ð±ÞÇÑ´Ù.
16.1.1. 2.0¿¡¼ 2.2·ÎÀÇ º¯È ¶ÀüüÀûÀÎ Ä¿³ÎÀÌ ¸ðµç º¯È¿¡ ´ëÇØ ÃæºÐÈ÷ ¹®¼ÈÇÏ°í ÀÖ´ÂÁö ¸ð¸£°Ú´Ù. ¿¹Á¦µéÀ» º¯È¯(ȤÀº ½ÇÁ¦·Î Emmanuel PapirakisÀÇ changes¸¦ Àû¿ë)ÇÏ´Â °úÁ¤¿¡¼ ³ª´Â ´ÙÀ½ÀÇ Â÷ÀÌÁ¡µéÀ» ¹ß°ßÇß´Ù. ³ª´Â ¸ðµâ ÇÁ·Î±×·¡¸Óµé(Áß¿¡¼ ƯÈ÷ ÀÌ Ã¥ÀÇ ÀÌÀü ÆǺÎÅÍ ¹è¿ö¿Â »ç¶÷µé°ú ³»°¡ ¾²°í »õ¹öÀüÀ¸·Î º¯È¯ÇÑ ±â¼úµé¿¡ °¡Àå Àͼ÷ÇÑ »ç¶÷µé)À» µ½±â À§Çؼ ±×°ÍµéÀ» ¸ðÁ¶¸® ³ª¿Çß´Ù.
2.2·Î º¯È¯Çϱ⸦ ¹Ù¶ó´Â À̵éÀ» À§ÇÑ Ãß°¡ÀûÀÎ ¸®¼Ò½ºµéÀº Richard GoochÀÇ »çÀÌÆ®¿¡¼ ãÀ» ¼ö ÀÖ´Ù.
asm/uaccess.h
put_user ³ª get_user°¡ ÇÊ¿äÇϸé, ±×°ÍÀ» Æ÷ÇÔ(#include)½ÃÄÑ¾ß ÇÑ´Ù.
get_user
2.2 ¹öÀü¿¡¼, get_user´Â À¯Àú ¸Þ¸ð¸®¿¡ ´ëÇÑ Æ÷ÀÎÅÍ¿Í Ä¿³Î ¸Þ¸ð¸®¿¡ µé¾îÀÖ´Â º¯¼ö¸¦ µÑ´Ù ¹Þ¾Æ¼ ÇØ´çµÇ´Â Á¤º¸µéÀ» ä¿î´Ù. ¿ì¸®°¡ ÀоîµéÀÌ´Â º¯¼ö°¡ 2¹ÙÀÌÆ® ȤÀº 4¹ÙÀÌÆ® ±æÀ̸¦ °¡Áú °æ¿ì, get_user°¡ Çѹø¿¡ 2¹ÙÀÌÆ® ¶Ç´Â 4¹ÙÀÌÆ®¸¦ ÀÐÀ» ¼ö Àֱ⠶§¹®ÀÌ´Ù.
file_operations
ÇöÀç ÀÌ ±¸Á¶Ã¼´Â open ÇÔ¼ö¿Í close ÇÔ¼ö »çÀÌ¿¡ flush ÇÔ¼ö¸¦ °¡Áö°í ÀÖ´Ù.
close in file_operations
2.2 ¹öÀü¿¡¼, close ÇÔ¼ö°¡ integer°ªÀ» ¹ÝȯÇϱ⠶§¹®¿¡, so it's allowed to fail.
file_operations¿¡¼ÀÇ read, write
ÀÌ ÇÔ¼öµé¿¡ ´ëÇÑ Çì´õ°¡ º¯°æµÇ¾ú´Ù. ±×°ÍµéÀº ÇöÀç integer ´ë½Å ssize_t¸¦ ¹ÝȯÇϸç, ÆĶó¹ÌÅÍ ¸ñ·Ïµµ ´Ù¸£´Ù. inode´Â ´õ ÀÌ»ó ÆĶó¹ÌÅÍ°¡ ¾Æ´Ï¸ç, ¹Ý´ë·Î ÆÄÀÏ¿¡ µé¾î°¡´Â ¿ÀÇÁ¼ÂÀº ÆĶó¹ÌÅÍ°¡ µÇ¾ú´Ù.
proc_register_dynamic
ÀÌ ÇÔ¼ö´Â ´õ ÀÌ»ó Á¸ÀçÇÏÁö ¾Ê´Â´Ù. ´ë½Å, Á¤±Ô proc_register¸¦ È£ÃâÇϸç, ±¸Á¶Ã¼ÀÇ inode Çʵ忡 zero¸¦ ³Ö´Â´Ù.
Signals
ŽºÅ© ³»ÀÇ ½Ã±×³ÎµéÀº ´õ ÀÌ»ó 32ºñÆ® Á¤¼ö°ªÀÌ ¾Æ´Ï°í _NSIG_WORDS Á¤¼öµéÀÇ ¹è¿ÀÌ´Ù.
queue_task_irq
ŽºÅ©¸¦ ÀÎÅÍ·´Æ® Çڵ鷯 ³»ºÎ¿¡¼ ¹ß»ýÇÏ°Ô²û ÁöÁ¤ÇÏ´Â °æ¿ì¿¡µµ queue_task_irq ´ë½Å queue_task¸¦ ¾²±â ¹Ù¶õ´Ù.
Module Parameters
´õ ÀÌ»ó ¸ðµâ ÆĶó¹ÌÅ͸¦ Àü¿ª º¯¼ö·Î¼ ¼±¾ðÇÏÁö ¾Ê¾Æµµ µÈ´Ù. 2.2¿¡¼µµ ¿ª½Ã MODULE_PARMÀ» ½á¼ ±×°ÍµéÀÇ Å¸ÀÔÀ» ¼±¾ðÇØÁÖµµ·Ï ÇÑ´Ù. ÀÌ°ÍÀº Ä¿´Ù¶õ ¹ßÀüÀÌ´Ù. ¿Ö³ÄÇϸé, ¸ðµâ·Î ÇÏ¿©±Ý digit(¿ªÀÚÁÖ: 0 ¶Ç´Â 1)À¸·Î ½ÃÀÛÇÏ´Â ¹®ÀÚ¿ ÆĶó¹ÌÅ͸¦ (¿¹ÄÁµ¥, È¥µ¿ÇÏÁö ¾Ê°íµµ) ¹ÞÀ» ¼ö ÀÖ°Ô µÇ¾ú±â ¶§¹®ÀÌ´Ù.
Symmetrical Multi-Processing
Ä¿³ÎÀº ´õ ÀÌ»ó °Å´ëÇÑ spinlock ¾È¿¡ Á¸ÀçÇÏÁö ¾ÊÀ¸¸ç, ÀÌ´Â Ä¿³Î¸ðµâÀÌ SMP¸¦ ¾Ë°í ÀÖ¾î¾ß ÇÔÀ» ÀǹÌÇÑ´Ù.
17. º¯°æÁ¡ ¶http://bbs.kldp.org/viewtopic.php?t=28376 À» º¸°í ÀÏ´Ü ½ÃÀÛÇÕ´Ï´Ù. --¼¼¹ú
C ¼Ò½º´Â ¿Ã¸®½Ã±â Àü¿¡ ÁÙ¸ÂÃãÀ» Çؼ ¿Ã·ÁÁֽñ⠹ٶø´Ï´Ù. --pyrasis
±¦ÇÑ ¿À¿ªÀ¸·Î µµ¿òÀº Ä¿³ç ¿ÀÇظ¸ ÁÖ´Â °ÍÀº ¾Æ´Ò·±Áö.. --HotPotato
ÁÙ¸ÂÃã(?)À» ½ÃÅ°·Á°í Çߴµ¥, Example 7-1, 7-2, 7-3, 8-1Àº ¹ø¿ª ¾ÈµÇ¾î ÀÖ´ø °Í ¸ÂÁÒ? --°ËÀºÇØ
|