x86.h static inline void insl(int port, void *addr, int cnt)

トップページ
jupiteroak.hatenablog.com


x86.h
https://github.com/mit-pdos/xv6-public/blob/master/x86.h#L12

static inline void
insl(int port, void *addr, int cnt)
{
  asm volatile("cld; 
                rep insl"
                : "=D" (addr), "=c" (cnt) 
                : "d" (port), "0" (addr), "1" (cnt)
                : "memory", "cc");
}

insl関数は、引数port(I/Oポートアドレス)で指定される入出力装置から 4×contバイトデータを読みとり、読み取ったデータを先頭アドレスが引数addrのメモリ領域に格納します。

引数 int port
入出力装置を指定するI/Oポートアドレスです。

引数 void *addr
読み取ったデータの格納先となるメモリ領域の先頭アドレスです。

引数 int cnt
指定された入出力装置から4バイトのデータを読み取る回数です。


処理の内容

インラインアセンブラ

asm volatile("cld; 
              rep insl"
              : "=D" (addr), "=c" (cnt) 
              : "d" (port), "0" (addr), "1" (cnt)
              : "memory", "cc");

関数内のインラインアセンブラを解釈すると以下のようになります。

アセンブリ言語命令

cld
rep insl"

インラインアセンブラの命令を実行する前の状態

・edxレジスタ(入力レジスタのリストにdで表記されている)
引数portの値が設定されています。
・ediレジスタ(入力レジスタのリストに0、出力レジスタのリストにDで表記されている)
引数addrの値が設定されています。
・ecxレジスタ(入力レジスタのリストに1、出力レジスタのリストにcで表記されている)
引数cntの値が設定されています。

cld

cld命令は、EFLGSレジスタのDFフラグ(bit10)をクリアします。DFフラグが0の時にストリング命令(movs、lods、cmps、inslなど)を実行すると、ediレジスタの値がインクリメントするようになります。

rep insl

repプレフィックス(リピートプレフィックス)を付けられた命令は、ecxレジスタに設定された値の回数分繰り返すように実行されます。
insl(insd)命令は、edxレジスタの値(I/Oポートアドレス)で指定される入出力装置から4バイトのデータを読み取り、読み取ったデータをediレジスタの値で指定されたメモリに格納します。
DFフラグが0の時(前のcld命令によってDFフラグが0の値になっている)、insl命令を実行するとediレジスタの値が4インクリメントされます。
repプレフィックスの効果により、この操作をecxレジスタに設定された値の回数分繰り返します。


参考
http://exlight.net/devel/8086/string.html
https://stackoverflow.com/questions/38410829/why-cant-find-the-insl-instruction-in-x86-document