x86.h static inline void lgdt(struct segdesc *p, int size)

トップページ
jupiteroak.hatenablog.com


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

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

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

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

lgdt関数は、引数pで指定されたGDTの先頭アドレス(グローバルディスクリプタテーブルの先頭アドレス)と引数sizeで指定されたGDTのサイズ(グローバルディスクリプタテーブルのサイズ)を、GDTR(グローバルディスクリプタテーブルレジスタ)に設定します。

引数 struct segdesc *p
GDTの先頭アドレスです。

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


処理の内容

前提

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

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

pd[0] = size-1;

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

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

pd[1] = (uint)p;

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

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

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

インラインアセンブラ

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

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

アセンブリ言語命令

lgdt %レジスタ

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

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

lgdt %レジスタ

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