x86.h static inline void lidt(struct gatedesc *p, int size)

トップページ
jupiteroak.hatenablog.com


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

static inline void lidt(struct gatedesc *p, int size)
{
  volatile ushort pd[3];

  pd[0] = size-1;
  pd[1] = (uint)p;
  pd[2] = (uint)p >> 16;

  asm volatile("lidt (%0)"
               :
               : "r" (pd));
}

lidt関数は、引数pで指定されたIDTの先頭アドレス(割り込みディスクリプタテーブルの先頭アドレス)と引数sizeで指定されたIDTのサイズ(割り込みディスクリプタテーブルのサイズ)を、IDTR(割り込みディスクリプタテーブルレジスタ)に設定します。

引数 struct gatedesc *p
IDTの先頭アドレスです。

引数 int size
IDTのサイズです。


処理の内容

前提

IDTRへの値の設定は、アセンブリ言語のlidt命令によって行われます。
アセンブリ言語のlidt命令はメインメモリ上のデータをIDTRにロードするので、あらかじめメインメモリ上にIDTRと同じデータ構造を用意する必要があります。

IDTRのbit15-0(リミット値)に設定する値を用意する

pd[0] = size-1;

IDTR様データ構造のbit15-0に、IDTのサイズ-1の値(バイト単位)を設定します。

IDTRのbit47-16(先頭アドレス値)に設定する値を用意する

pd[1] = (uint)p;

IDTR様データ構造のbit31-16に、IDTの先頭アドレスの下位16bitを設定します。

pd[2] = (uint)p >> 16;

IDTR様データ構造のbit47-16に、IDTの先頭アドレスの上位16bitを設定します。

インラインアセンブラ

asm volatile("lidt (%0)"
               : 
               : "r" (pd));

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

アセンブリ言語命令

lidt %レジスタ

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

・eax,ebx,ecx,edx,esi,ediレジスタのいずれか(入力レジスタのリストにrで表記されている)
引数pdの値が設定されています。

lidt %レジスタ

lidt命令により、レジスタで指定されたアドレスから配置してある48bitのデータ構造の値がIDTRにロードされます。