Linux Kernel

「Linux Kernel」の編集履歴(バックアップ)一覧はこちら

Linux Kernel」(2008/04/12 (土) 19:22:05) の最新版変更点

追加された行は緑色になります。

削除された行は赤色になります。

*Linux Kernel Linuxカーネルについてまなんだことを書きます。 Linuxカーネルというくくりでいいのかよくわからないことも書きます。 Linuxカーネルに付随するいくつかのことも書きます。 **関数 ***outb_p(char addr , port) portにaddrを書き込みます。 これをしたあとにinb_p(port)とかやったりします。 manページには以下のように書いてあります。 the _p-suffix functions pause until the I/O completes I/Oが完了するまで待つとありますね。 RTCの読み込みとかに使います。 makeした.oファイルを逆アセンブルすると、 outb_p (addr , 0x70 ) が out %al,$0x70 call *0xc8 になったりします。 call *0xc8 ってなんでしょうね。 なにか待つだけのサブルーチンなんでしょうかね。 と思ってテスト用のデバイスドライバを書いてコンパイルしたものをを逆アセンブルしてみたら、上のcallの部分が out %al,0x80 になっていました。もうちょっと調べたら、マクロ定義がio.hにありました。 00028 #ifdef SLOW_IO_BY_JUMPING 00029 #define __SLOW_DOWN_IO __asm__ __volatile__("jmp 1f\n1:\tjmp 1f\n1:") 00030 #else 00031 #define __SLOW_DOWN_IO __asm__ __volatile__("outb %al,$0x80") 00032 #endif 最終的には outb_p (addr , 0x70 ( が out %al,$0x70 out %al,0x80 になるようです。 **rtl8139(蟹チップ)のドライバ パケット送信について調べてみた。 ドライバのソースは /drivers/net/8139too.c パケット送信は以下の関数で行われている模様。 626 static int rtl8139_start_xmit (struct sk_buff *skb, 627 struct net_device *dev); その関数は以下の様になっています。 #highlight(C){{ 1706 static int rtl8139_start_xmit (struct sk_buff *skb, struct net_device *dev) 1707 { 1708 struct rtl8139_private *tp = netdev_priv(dev); 1709 void __iomem *ioaddr = tp->mmio_addr; 1710 unsigned int entry; 1711 unsigned int len = skb->len; 1712 unsigned long flags; 1713 1714 /* Calculate the next Tx descriptor entry. */ 1715 entry = tp->cur_tx % NUM_TX_DESC; 1716 1717 /* Note: the chip doesn't have auto-pad! */ 1718 if (likely(len < TX_BUF_SIZE)) { 1719 if (len < ETH_ZLEN) 1720 memset(tp->tx_buf[entry], 0, ETH_ZLEN); 1721 skb_copy_and_csum_dev(skb, tp->tx_buf[entry]); 1722 dev_kfree_skb(skb); 1723 } else { 1724 dev_kfree_skb(skb); 1725 tp->stats.tx_dropped++; 1726 return 0; 1727 } 1728 1729 spin_lock_irqsave(&tp->lock, flags); 1730 RTL_W32_F (TxStatus0 + (entry * sizeof (u32)), 1731 tp->tx_flag | max(len, (unsigned int)ETH_ZLEN)); 1732 1733 dev->trans_start = jiffies; 1734 1735 tp->cur_tx++; 1736 wmb(); 1737 1738 if ((tp->cur_tx - NUM_TX_DESC) == tp->dirty_tx) 1739 netif_stop_queue (dev); 1740 spin_unlock_irqrestore(&tp->lock, flags); 1741 1742 if (netif_msg_tx_queued(tp)) 1743 printk (KERN_DEBUG "%s: Queued Tx packet size %u to slot %d.\n", 1744 dev->name, len, entry); 1745 1746 return 0; 1747 } }} 関数の実態を探ります。まずはこのあたり。 #highlight(C){{ 1718 if (likely(len < TX_BUF_SIZE)) { 1719 if (len < ETH_ZLEN) 1720 memset(tp->tx_buf[entry], 0, ETH_ZLEN); 1721 skb_copy_and_csum_dev(skb, tp->tx_buf[entry]); 1722 dev_kfree_skb(skb); 1723 } else { 1724 dev_kfree_skb(skb); 1725 tp->stats.tx_dropped++; 1726 return 0; 1727 } }} ***likely() -/src/linux-2.6.18/include/linux/compiler.h 62 #define likely(x) __builtin_expect(!!(x), 1) この先はありません。今の僕には理解できませんでした。 ***memset() -/src/linux-2.6.18/arch/i386/lib/memcpy.c 17 void *memset(void *s, int c, size_t count) 18 { 19 return __memset(s, c, count); 20 } ↓ -/src/linux-2.6.18/include/asm-i386/string.h 462 #define __memset(s, c, count) \ 463 (__builtin_constant_p(count) ? \ 464 __constant_count_memset((s),(c),(count)) : \ 465 __memset_generic((s),(c),(count))) ( A ? B : C)の形の3項演算子ですね。Aが真ならB、そうでないならCという感じだったと思います。 ****__builtin_constant_p() GNUコンパイラの組み込み関数だそうです。これも今の僕には理解できませんでした。こちらに詳しく載っています。 [[参考URL>>http://caspar.hazymoon.jp/OpenBSD/docs/gcc-j/Other-Builtins.html]] ****__constant_count_memset() -/src/linux-2.6.18/include/asm-i386/string.h 361 /* we might want to write optimized versions of these later */ 362 #define __constant_count_memset(s,c,count) __memset_generic((s),(c),(count)) ****__memset_generic() -/src/linux-2.6.18/include/asm-i386/string.h 349 static inline void * __memset_generic(void * s, char c,size_t count) 350 { 351 int d0, d1; 352 __asm__ __volatile__( 353 "rep\n\t" 354 "stosb" 355 : "=&c" (d0), "=&D" (d1) 356 :"a" (c),"1" (s),"0" (count) 357 :"memory"); 358 return s; 359 } ということでmemsetはインラインアセンブラになるみたいですね。 インラインアセンブラの制約条件などについては[[こちら>http://yashiromann.sakura.ne.jp/memo/GCC-Inline-Assembly-HOWTO.html#ss6.1]]に詳しく書いてあります。 [[http://yashiromann.sakura.ne.jp/memo/GCC-Inline-Assembly-HOWTO.html#ss6.1>http://yashiromann.sakura.ne.jp/memo/GCC-Inline-Assembly-HOWTO.html#ss6.1]] ***skb_copy_and_csum_dev() -/src/linux-2.6.18/net/core/skbuff.c 1396 void skb_copy_and_csum_dev(const struct sk_buff *skb, u8 *to) 1397 { 1398 unsigned int csum; 1399 long csstart; 1400 1401 if (skb->ip_summed == CHECKSUM_HW) 1402 csstart = skb->h.raw - skb->data; 1403 else 1404 csstart = skb_headlen(skb); 1405 1406 BUG_ON(csstart > skb_headlen(skb)); 1407 1408 memcpy(to, skb->data, csstart); 1409 1410 csum = 0; 1411 if (csstart != skb->len) 1412 csum = skb_copy_and_csum_bits (skb, csstart, to + csstart, 1413 skb->len - csstart, 0); 1414 1415 if (skb->ip_summed == CHECKSUM_HW) { 1416 long csstuff = csstart + skb->csum; 1417 1418 *((unsigned short *)(to + sstuff)) = csum_fold(csum); 1419 } 1420 } です。関数としては -BUG_ON -memcpy -skb_copy_and_csum_bits -csum_fold ですね。 ****BUG_ON() 探したら定義が2つあった。 BUG_ON()一つ目。 -/src/linux-2.6.18/include/asm-generic/bug.h 14 #ifndef HAVE_ARCH_BUG_ON 15 #define BUG_ON(condition) do { if (unlikely((condition)!=0)) BUG(); } while(0) 16 #endif 中では -unlikely() -BUG() が実行されています。BUG()も複数定義があるのでよくわかりません。 一応二つの定義をこぴぺしておきます。 *****BUG() 一つ目。 -/src/linux-2.6.18/include/asm-generic/bug.h 6 #ifdef CONFIG_BUG 7 #ifndef HAVE_ARCH_BUG 8 #define BUG() do { \ 9 printk("BUG: failure at %s:%d/%s()!\n", __FILE__, __LINE__, __FUNCTION__); \ 10 panic("BUG!"); \ 11 } while (0) 12 #endif 二つ目。 -/src/linux-2.6.18/include/asm-generic/bug.h 27 #else /* !CONFIG_BUG */ 28 #ifndef HAVE_ARCH_BUG 29 #define BUG() 30 #endif BUG_ON()2つ目。 -/src/linux-2.6.18/include/asm-generic/bug.h 32 #ifndef HAVE_ARCH_BUG_ON 33 #define BUG_ON(condition) do { if (condition) ; } while(0) 34 #endif なんかコンパイルフラグですね。よくわかりません。 ****memcpy() -/src/linux-2.6.18/arch/i386/lib/memcpy.c 7 void *memcpy(void *to, const void *from, size_t n) 8 { 9 #ifdef CONFIG_X86_USE_3DNOW 10 return __memcpy3d(to, from, n); 11 #else 12 return __memcpy(to, from, n); 13 #endif 14 } コンパイルフラグですね。 -__memcpy3d -__memcpy の二つです。 *****__memcpy3d() -/src/linux-2.6.18/include/asm-i386/string.h 300 static __inline__ void *__memcpy3d(void *to, const void *from, size_t len) 301 { 302 if (len < 512) 303 return __memcpy(to, from, len); 304 return _mmx_memcpy(to, from, len); 305 } _mmx_memcpy()は結構長いインラインアセンブラでした。 -src/linux-2.6.18/arch/i386/lib/mmx.c にありあます。長いので省きます。コピーをする長さで条件分岐しているんですね。mmxはmulti media extentionの略らしいです。 *****__memcpy() -/src/linux-2.6.18/include/asm-i386/string.h 203 static __always_inline void * __memcpy(void * to, const void * from, size_t n) 204 { 205 int d0, d1, d2; 206 __asm__ __volatile__( 207 "rep ; movsl\n\t" 208 "movl %4,%%ecx\n\t" 209 "andl $3,%%ecx\n\t" 210 #if 1 /* want to pay 2 byte penalty for a chance to skip microcoded rep? */ 211 "jz 1f\n\t" 212 #endif 213 "rep ; movsb\n\t" 214 "1:" 215 : "=&c" (d0), "=&D" (d1), "=&S" (d2) 216 : "0" (n/4), "g" (n), "1" ((long) to), "2" ((long) from) 217 : "memory"); 218 return (to); 219 } こちらはインラインアセンブラになりますね。 ****skb_copy_and_csum_bits() 長い・・・ -/src/linux-2.6.18/net/core/skbuff.c #highlight(C){{ 1317 unsigned int skb_copy_and_csum_bits(const struct sk_buff *skb, int offset, 1318 u8 *to, int len, unsigned int csum) 1319 { 1320 int start = skb_headlen(skb); 1321 int i, copy = start - offset; 1322 int pos = 0; 1323 1324 /* Copy header. */ 1325 if (copy > 0) { 1326 if (copy > len) 1327 copy = len; 1328 csum = csum_partial_copy_nocheck(skb->data + offset, to, 1329 copy, csum); 1330 if ((len -= copy) == 0) 1331 return csum; 1332 offset += copy; 1333 to += copy; 1334 pos = copy; 1335 } 1336 1337 for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) { 1338 int end; 1339 1340 BUG_TRAP(start <= offset + len); 1341 1342 end = start + skb_shinfo(skb)->frags[i].size; 1343 if ((copy = end - offset) > 0) { 1344 unsigned int csum2; 1345 u8 *vaddr; 1346 skb_frag_t *frag = &skb_shinfo(skb)->frags[i]; 1347 1348 if (copy > len) 1349 copy = len; 1350 vaddr = kmap_skb_frag(frag); 1351 csum2 = csum_partial_copy_nocheck(vaddr + 1352 frag->page_offset + 1353 offset - start, to, 1354 copy, 0); 1355 kunmap_skb_frag(vaddr); 1356 csum = csum_block_add(csum, csum2, pos); 1357 if (!(len -= copy)) 1358 return csum; 1359 offset += copy; 1360 to += copy; 1361 pos += copy; 1362 } 1363 start = end; 1364 } 1365 1366 if (skb_shinfo(skb)->frag_list) { 1367 struct sk_buff *list = skb_shinfo(skb)->frag_list; 1368 1369 for (; list; list = list->next) { 1370 unsigned int csum2; 1371 int end; 1372 1373 BUG_TRAP(start <= offset + len); 1374 1375 end = start + list->len; 1376 if ((copy = end - offset) > 0) { 1377 if (copy > len) 1378 copy = len; 1379 csum2 = skb_copy_and_csum_bits(list, 1380 offset - start, 1381 to, copy, 0); 1382 csum = csum_block_add(csum, csum2, pos); 1383 if ((len -= copy) == 0) 1384 return csum; 1385 offset += copy; 1386 to += copy; 1387 pos += copy; 1388 } 1389 start = end; 1390 } 1391 } 1392 BUG_ON(len); 1393 return csum; 1394 } 1395 }} これの実態を追いかけるのは面倒だなー。省略。 ****csum_fold() -/src/linux-2.6.18/include/asm-i386/checksum.h #highlight(c){{ 99 static inline unsigned int csum_fold(unsigned int sum) 100 { 101 __asm__( 102 "addl %1, %0 ;\n" 103 "adcl $0xffff, %0 ;\n" 104 : "=r" (sum) 105 : "r" (sum << 16), "0" (sum & 0xffff0000) 106 ); 107 return (~sum) >> 16; 108 } }}
*Linux Kernel Linuxカーネルについてまなんだことを書きます。 Linuxカーネルというくくりでいいのかよくわからないことも書きます。 Linuxカーネルに付随するいくつかのことも書きます。 **関数 ***outb_p(char addr , port) portにaddrを書き込みます。 これをしたあとにinb_p(port)とかやったりします。 manページには以下のように書いてあります。 the _p-suffix functions pause until the I/O completes I/Oが完了するまで待つとありますね。 RTCの読み込みとかに使います。 makeした.oファイルを逆アセンブルすると、 outb_p (addr , 0x70 ) が out %al,$0x70 call *0xc8 になったりします。 call *0xc8 ってなんでしょうね。 なにか待つだけのサブルーチンなんでしょうかね。 と思ってテスト用のデバイスドライバを書いてコンパイルしたものをを逆アセンブルしてみたら、上のcallの部分が out %al,0x80 になっていました。もうちょっと調べたら、マクロ定義がio.hにありました。 00028 #ifdef SLOW_IO_BY_JUMPING 00029 #define __SLOW_DOWN_IO __asm__ __volatile__("jmp 1f\n1:\tjmp 1f\n1:") 00030 #else 00031 #define __SLOW_DOWN_IO __asm__ __volatile__("outb %al,$0x80") 00032 #endif 最終的には outb_p (addr , 0x70 ( が out %al,$0x70 out %al,0x80 になるようです。

表示オプション

横に並べて表示:
変化行の前後のみ表示:
ツールボックス

下から選んでください:

新しいページを作成する
ヘルプ / FAQ もご覧ください。